xref: /openbsd-src/usr.bin/dig/lib/dns/rdata/in_1/a6_38.c (revision 99fd087599a8791921855f21bd7e36130f39aadc)
1 /*
2  * Copyright (C) Internet Systems Consortium, Inc. ("ISC")
3  *
4  * Permission to use, copy, modify, and/or distribute this software for any
5  * purpose with or without fee is hereby granted, provided that the above
6  * copyright notice and this permission notice appear in all copies.
7  *
8  * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
9  * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
10  * AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
11  * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
12  * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
13  * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
14  * PERFORMANCE OF THIS SOFTWARE.
15  */
16 
17 /* $Id: a6_38.c,v 1.12 2020/02/26 18:47:59 florian Exp $ */
18 
19 /* RFC2874 */
20 
21 #ifndef RDATA_IN_1_A6_28_C
22 #define RDATA_IN_1_A6_28_C
23 
24 #include <isc/net.h>
25 
26 static inline isc_result_t
27 totext_in_a6(ARGS_TOTEXT) {
28 	isc_region_t sr, ar;
29 	unsigned char addr[16];
30 	unsigned char prefixlen;
31 	unsigned char octets;
32 	unsigned char mask;
33 	char buf[sizeof("128")];
34 	dns_name_t name;
35 	dns_name_t prefix;
36 	isc_boolean_t sub;
37 
38 	REQUIRE(rdata->type == dns_rdatatype_a6);
39 	REQUIRE(rdata->rdclass == dns_rdataclass_in);
40 	REQUIRE(rdata->length != 0);
41 
42 	dns_rdata_toregion(rdata, &sr);
43 	prefixlen = sr.base[0];
44 	INSIST(prefixlen <= 128);
45 	isc_region_consume(&sr, 1);
46 	snprintf(buf, sizeof(buf), "%u", prefixlen);
47 	RETERR(isc_str_tobuffer(buf, target));
48 	RETERR(isc_str_tobuffer(" ", target));
49 
50 	if (prefixlen != 128) {
51 		octets = prefixlen/8;
52 		memset(addr, 0, sizeof(addr));
53 		memmove(&addr[octets], sr.base, 16 - octets);
54 		mask = 0xff >> (prefixlen % 8);
55 		addr[octets] &= mask;
56 		ar.base = addr;
57 		ar.length = sizeof(addr);
58 		RETERR(inet_totext(AF_INET6, &ar, target));
59 		isc_region_consume(&sr, 16 - octets);
60 	}
61 
62 	if (prefixlen == 0)
63 		return (ISC_R_SUCCESS);
64 
65 	RETERR(isc_str_tobuffer(" ", target));
66 	dns_name_init(&name, NULL);
67 	dns_name_init(&prefix, NULL);
68 	dns_name_fromregion(&name, &sr);
69 	sub = name_prefix(&name, tctx->origin, &prefix);
70 	return (dns_name_totext(&prefix, sub, target));
71 }
72 
73 static inline isc_result_t
74 fromwire_in_a6(ARGS_FROMWIRE) {
75 	isc_region_t sr;
76 	unsigned char prefixlen;
77 	unsigned char octets;
78 	unsigned char mask;
79 	dns_name_t name;
80 
81 	REQUIRE(type == dns_rdatatype_a6);
82 	REQUIRE(rdclass == dns_rdataclass_in);
83 
84 	UNUSED(type);
85 	UNUSED(rdclass);
86 
87 	dns_decompress_setmethods(dctx, DNS_COMPRESS_NONE);
88 
89 	isc_buffer_activeregion(source, &sr);
90 	/*
91 	 * Prefix length.
92 	 */
93 	if (sr.length < 1)
94 		return (ISC_R_UNEXPECTEDEND);
95 	prefixlen = sr.base[0];
96 	if (prefixlen > 128)
97 		return (ISC_R_RANGE);
98 	isc_region_consume(&sr, 1);
99 	RETERR(isc_mem_tobuffer(target, &prefixlen, 1));
100 	isc_buffer_forward(source, 1);
101 
102 	/*
103 	 * Suffix.
104 	 */
105 	if (prefixlen != 128) {
106 		octets = 16 - prefixlen / 8;
107 		if (sr.length < octets)
108 			return (ISC_R_UNEXPECTEDEND);
109 		mask = 0xff >> (prefixlen % 8);
110 		sr.base[0] &= mask;	/* Ensure pad bits are zero. */
111 		RETERR(isc_mem_tobuffer(target, sr.base, octets));
112 		isc_buffer_forward(source, octets);
113 	}
114 
115 	if (prefixlen == 0)
116 		return (ISC_R_SUCCESS);
117 
118 	dns_name_init(&name, NULL);
119 	return (dns_name_fromwire(&name, source, dctx, options, target));
120 }
121 
122 static inline isc_result_t
123 towire_in_a6(ARGS_TOWIRE) {
124 	isc_region_t sr;
125 	dns_name_t name;
126 	dns_offsets_t offsets;
127 	unsigned char prefixlen;
128 	unsigned char octets;
129 
130 	REQUIRE(rdata->type == dns_rdatatype_a6);
131 	REQUIRE(rdata->rdclass == dns_rdataclass_in);
132 	REQUIRE(rdata->length != 0);
133 
134 	dns_compress_setmethods(cctx, DNS_COMPRESS_NONE);
135 	dns_rdata_toregion(rdata, &sr);
136 	prefixlen = sr.base[0];
137 	INSIST(prefixlen <= 128);
138 
139 	octets = 1 + 16 - prefixlen / 8;
140 	RETERR(isc_mem_tobuffer(target, sr.base, octets));
141 	isc_region_consume(&sr, octets);
142 
143 	if (prefixlen == 0)
144 		return (ISC_R_SUCCESS);
145 
146 	dns_name_init(&name, offsets);
147 	dns_name_fromregion(&name, &sr);
148 	return (dns_name_towire(&name, cctx, target));
149 }
150 
151 #endif	/* RDATA_IN_1_A6_38_C */
152