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