1/*	$NetBSD: aaaa_28.c,v 1.1 2024/02/18 20:57:46 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/* RFC1886 */
17
18#ifndef RDATA_IN_1_AAAA_28_C
19#define RDATA_IN_1_AAAA_28_C
20
21#include <isc/net.h>
22
23#define RRTYPE_AAAA_ATTRIBUTES (0)
24
25static isc_result_t
26fromtext_in_aaaa(ARGS_FROMTEXT) {
27	isc_token_t token;
28	unsigned char addr[16];
29	isc_region_t region;
30
31	REQUIRE(type == dns_rdatatype_aaaa);
32	REQUIRE(rdclass == dns_rdataclass_in);
33
34	UNUSED(type);
35	UNUSED(origin);
36	UNUSED(options);
37	UNUSED(rdclass);
38	UNUSED(callbacks);
39
40	RETERR(isc_lex_getmastertoken(lexer, &token, isc_tokentype_string,
41				      false));
42
43	if (inet_pton(AF_INET6, DNS_AS_STR(token), addr) != 1) {
44		RETTOK(DNS_R_BADAAAA);
45	}
46	isc_buffer_availableregion(target, &region);
47	if (region.length < 16) {
48		return (ISC_R_NOSPACE);
49	}
50	memmove(region.base, addr, 16);
51	isc_buffer_add(target, 16);
52	return (ISC_R_SUCCESS);
53}
54
55static isc_result_t
56totext_in_aaaa(ARGS_TOTEXT) {
57	isc_region_t region;
58
59	REQUIRE(rdata->type == dns_rdatatype_aaaa);
60	REQUIRE(rdata->rdclass == dns_rdataclass_in);
61	REQUIRE(rdata->length == 16);
62
63	if ((tctx->flags & DNS_STYLEFLAG_EXPANDAAAA) != 0) {
64		char buf[5 * 8];
65		const char *sep = "";
66		int i, n;
67		unsigned int len = 0;
68
69		for (i = 0; i < 16; i += 2) {
70			INSIST(len < sizeof(buf));
71			n = snprintf(buf + len, sizeof(buf) - len, "%s%02x%02x",
72				     sep, rdata->data[i], rdata->data[i + 1]);
73			if (n < 0) {
74				return (ISC_R_FAILURE);
75			}
76			len += n;
77			sep = ":";
78		}
79		return (str_totext(buf, target));
80	}
81	dns_rdata_toregion(rdata, &region);
82	return (inet_totext(AF_INET6, tctx->flags, &region, target));
83}
84
85static isc_result_t
86fromwire_in_aaaa(ARGS_FROMWIRE) {
87	isc_region_t sregion;
88	isc_region_t tregion;
89
90	REQUIRE(type == dns_rdatatype_aaaa);
91	REQUIRE(rdclass == dns_rdataclass_in);
92
93	UNUSED(type);
94	UNUSED(dctx);
95	UNUSED(options);
96	UNUSED(rdclass);
97
98	isc_buffer_activeregion(source, &sregion);
99	isc_buffer_availableregion(target, &tregion);
100	if (sregion.length < 16) {
101		return (ISC_R_UNEXPECTEDEND);
102	}
103	if (tregion.length < 16) {
104		return (ISC_R_NOSPACE);
105	}
106
107	memmove(tregion.base, sregion.base, 16);
108	isc_buffer_forward(source, 16);
109	isc_buffer_add(target, 16);
110	return (ISC_R_SUCCESS);
111}
112
113static isc_result_t
114towire_in_aaaa(ARGS_TOWIRE) {
115	isc_region_t region;
116
117	UNUSED(cctx);
118
119	REQUIRE(rdata->type == dns_rdatatype_aaaa);
120	REQUIRE(rdata->rdclass == dns_rdataclass_in);
121	REQUIRE(rdata->length == 16);
122
123	isc_buffer_availableregion(target, &region);
124	if (region.length < rdata->length) {
125		return (ISC_R_NOSPACE);
126	}
127	memmove(region.base, rdata->data, rdata->length);
128	isc_buffer_add(target, 16);
129	return (ISC_R_SUCCESS);
130}
131
132static int
133compare_in_aaaa(ARGS_COMPARE) {
134	isc_region_t r1;
135	isc_region_t r2;
136
137	REQUIRE(rdata1->type == rdata2->type);
138	REQUIRE(rdata1->rdclass == rdata2->rdclass);
139	REQUIRE(rdata1->type == dns_rdatatype_aaaa);
140	REQUIRE(rdata1->rdclass == dns_rdataclass_in);
141	REQUIRE(rdata1->length == 16);
142	REQUIRE(rdata2->length == 16);
143
144	dns_rdata_toregion(rdata1, &r1);
145	dns_rdata_toregion(rdata2, &r2);
146	return (isc_region_compare(&r1, &r2));
147}
148
149static isc_result_t
150fromstruct_in_aaaa(ARGS_FROMSTRUCT) {
151	dns_rdata_in_aaaa_t *aaaa = source;
152
153	REQUIRE(type == dns_rdatatype_aaaa);
154	REQUIRE(rdclass == dns_rdataclass_in);
155	REQUIRE(aaaa != NULL);
156	REQUIRE(aaaa->common.rdtype == type);
157	REQUIRE(aaaa->common.rdclass == rdclass);
158
159	UNUSED(type);
160	UNUSED(rdclass);
161
162	return (mem_tobuffer(target, aaaa->in6_addr.s6_addr, 16));
163}
164
165static isc_result_t
166tostruct_in_aaaa(ARGS_TOSTRUCT) {
167	dns_rdata_in_aaaa_t *aaaa = target;
168	isc_region_t r;
169
170	REQUIRE(rdata->type == dns_rdatatype_aaaa);
171	REQUIRE(rdata->rdclass == dns_rdataclass_in);
172	REQUIRE(aaaa != NULL);
173	REQUIRE(rdata->length == 16);
174
175	UNUSED(mctx);
176
177	aaaa->common.rdclass = rdata->rdclass;
178	aaaa->common.rdtype = rdata->type;
179	ISC_LINK_INIT(&aaaa->common, link);
180
181	dns_rdata_toregion(rdata, &r);
182	INSIST(r.length == 16);
183	memmove(aaaa->in6_addr.s6_addr, r.base, 16);
184
185	return (ISC_R_SUCCESS);
186}
187
188static void
189freestruct_in_aaaa(ARGS_FREESTRUCT) {
190	dns_rdata_in_aaaa_t *aaaa = source;
191
192	REQUIRE(aaaa != NULL);
193	REQUIRE(aaaa->common.rdclass == dns_rdataclass_in);
194	REQUIRE(aaaa->common.rdtype == dns_rdatatype_aaaa);
195
196	UNUSED(aaaa);
197}
198
199static isc_result_t
200additionaldata_in_aaaa(ARGS_ADDLDATA) {
201	REQUIRE(rdata->type == dns_rdatatype_aaaa);
202	REQUIRE(rdata->rdclass == dns_rdataclass_in);
203
204	UNUSED(rdata);
205	UNUSED(add);
206	UNUSED(arg);
207
208	return (ISC_R_SUCCESS);
209}
210
211static isc_result_t
212digest_in_aaaa(ARGS_DIGEST) {
213	isc_region_t r;
214
215	REQUIRE(rdata->type == dns_rdatatype_aaaa);
216	REQUIRE(rdata->rdclass == dns_rdataclass_in);
217
218	dns_rdata_toregion(rdata, &r);
219
220	return ((digest)(arg, &r));
221}
222
223static bool
224checkowner_in_aaaa(ARGS_CHECKOWNER) {
225	dns_name_t prefix, suffix;
226
227	REQUIRE(type == dns_rdatatype_aaaa);
228	REQUIRE(rdclass == dns_rdataclass_in);
229
230	UNUSED(type);
231	UNUSED(rdclass);
232
233	/*
234	 * Handle Active Directory gc._msdcs.<forest> name.
235	 */
236	if (dns_name_countlabels(name) > 2U) {
237		dns_name_init(&prefix, NULL);
238		dns_name_init(&suffix, NULL);
239		dns_name_split(name, dns_name_countlabels(name) - 2, &prefix,
240			       &suffix);
241		if (dns_name_equal(&gc_msdcs, &prefix) &&
242		    dns_name_ishostname(&suffix, false))
243		{
244			return (true);
245		}
246	}
247
248	return (dns_name_ishostname(name, wildcard));
249}
250
251static bool
252checknames_in_aaaa(ARGS_CHECKNAMES) {
253	REQUIRE(rdata->type == dns_rdatatype_aaaa);
254	REQUIRE(rdata->rdclass == dns_rdataclass_in);
255
256	UNUSED(rdata);
257	UNUSED(owner);
258	UNUSED(bad);
259
260	return (true);
261}
262
263static int
264casecompare_in_aaaa(ARGS_COMPARE) {
265	return (compare_in_aaaa(rdata1, rdata2));
266}
267#endif /* RDATA_IN_1_AAAA_28_C */
268