xref: /netbsd-src/external/mpl/bind/dist/lib/dns/rdata/generic/nxt_30.c (revision bcda20f65a8566e103791ec395f7f499ef322704)
1 /*	$NetBSD: nxt_30.c,v 1.9 2025/01/26 16:25:32 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 /* RFC2535 */
17 
18 #ifndef RDATA_GENERIC_NXT_30_C
19 #define RDATA_GENERIC_NXT_30_C
20 
21 /*
22  * The attributes do not include DNS_RDATATYPEATTR_SINGLETON
23  * because we must be able to handle a parent/child NXT pair.
24  */
25 #define RRTYPE_NXT_ATTRIBUTES (0)
26 
27 static isc_result_t
28 fromtext_nxt(ARGS_FROMTEXT) {
29 	isc_token_t token;
30 	dns_name_t name;
31 	isc_buffer_t buffer;
32 	char *e;
33 	unsigned char bm[8 * 1024]; /* 64k bits */
34 	dns_rdatatype_t covered;
35 	dns_rdatatype_t maxcovered = 0;
36 	bool first = true;
37 	long n;
38 
39 	REQUIRE(type == dns_rdatatype_nxt);
40 
41 	UNUSED(type);
42 	UNUSED(rdclass);
43 	UNUSED(callbacks);
44 
45 	/*
46 	 * Next domain.
47 	 */
48 	RETERR(isc_lex_getmastertoken(lexer, &token, isc_tokentype_string,
49 				      false));
50 	dns_name_init(&name, NULL);
51 	buffer_fromregion(&buffer, &token.value.as_region);
52 	if (origin == NULL) {
53 		origin = dns_rootname;
54 	}
55 	RETTOK(dns_name_fromtext(&name, &buffer, origin, options, target));
56 
57 	memset(bm, 0, sizeof(bm));
58 	do {
59 		RETERR(isc_lex_getmastertoken(lexer, &token,
60 					      isc_tokentype_string, true));
61 		if (token.type != isc_tokentype_string) {
62 			break;
63 		}
64 		n = strtol(DNS_AS_STR(token), &e, 10);
65 		if (e != DNS_AS_STR(token) && *e == '\0') {
66 			covered = (dns_rdatatype_t)n;
67 		} else if (dns_rdatatype_fromtext(&covered,
68 						  &token.value.as_textregion) ==
69 			   DNS_R_UNKNOWN)
70 		{
71 			RETTOK(DNS_R_UNKNOWN);
72 		}
73 		/*
74 		 * NXT is only specified for types 1..127.
75 		 */
76 		if (covered < 1 || covered > 127) {
77 			return ISC_R_RANGE;
78 		}
79 		if (first || covered > maxcovered) {
80 			maxcovered = covered;
81 		}
82 		first = false;
83 		bm[covered / 8] |= (0x80 >> (covered % 8));
84 	} while (1);
85 	isc_lex_ungettoken(lexer, &token);
86 	if (first) {
87 		return ISC_R_SUCCESS;
88 	}
89 	n = (maxcovered + 8) / 8;
90 	return mem_tobuffer(target, bm, n);
91 }
92 
93 static isc_result_t
94 totext_nxt(ARGS_TOTEXT) {
95 	isc_region_t sr;
96 	unsigned int i, j, opts;
97 	dns_name_t name;
98 	dns_name_t prefix;
99 
100 	REQUIRE(rdata->type == dns_rdatatype_nxt);
101 	REQUIRE(rdata->length != 0);
102 
103 	dns_name_init(&name, NULL);
104 	dns_name_init(&prefix, NULL);
105 	dns_rdata_toregion(rdata, &sr);
106 	dns_name_fromregion(&name, &sr);
107 	isc_region_consume(&sr, name_length(&name));
108 	opts = name_prefix(&name, tctx->origin, &prefix) ? DNS_NAME_OMITFINALDOT
109 							 : 0;
110 	RETERR(dns_name_totext(&prefix, opts, target));
111 
112 	for (i = 0; i < sr.length; i++) {
113 		if (sr.base[i] != 0) {
114 			for (j = 0; j < 8; j++) {
115 				if ((sr.base[i] & (0x80 >> j)) != 0) {
116 					{
117 						dns_rdatatype_t t = i * 8 + j;
118 						RETERR(str_totext(" ", target));
119 						if (dns_rdatatype_isknown(t)) {
120 							RETERR(dns_rdatatype_totext(
121 								t, target));
122 						} else {
123 							char buf[sizeof("6553"
124 									"5")];
125 							snprintf(buf,
126 								 sizeof(buf),
127 								 "%u", t);
128 							RETERR(str_totext(
129 								buf, target));
130 						}
131 					}
132 				}
133 			}
134 		}
135 	}
136 	return ISC_R_SUCCESS;
137 }
138 
139 static isc_result_t
140 fromwire_nxt(ARGS_FROMWIRE) {
141 	isc_region_t sr;
142 	dns_name_t name;
143 
144 	REQUIRE(type == dns_rdatatype_nxt);
145 
146 	UNUSED(type);
147 	UNUSED(rdclass);
148 
149 	dctx = dns_decompress_setpermitted(dctx, false);
150 
151 	dns_name_init(&name, NULL);
152 	RETERR(dns_name_fromwire(&name, source, dctx, target));
153 
154 	isc_buffer_activeregion(source, &sr);
155 	if (sr.length > 0 && ((sr.base[0] & 0x80) != 0 || sr.length > 16 ||
156 			      sr.base[sr.length - 1] == 0))
157 	{
158 		return DNS_R_BADBITMAP;
159 	}
160 	RETERR(mem_tobuffer(target, sr.base, sr.length));
161 	isc_buffer_forward(source, sr.length);
162 	return ISC_R_SUCCESS;
163 }
164 
165 static isc_result_t
166 towire_nxt(ARGS_TOWIRE) {
167 	isc_region_t sr;
168 	dns_name_t name;
169 	dns_offsets_t offsets;
170 
171 	REQUIRE(rdata->type == dns_rdatatype_nxt);
172 	REQUIRE(rdata->length != 0);
173 
174 	dns_compress_setpermitted(cctx, false);
175 	dns_name_init(&name, offsets);
176 	dns_rdata_toregion(rdata, &sr);
177 	dns_name_fromregion(&name, &sr);
178 	isc_region_consume(&sr, name_length(&name));
179 	RETERR(dns_name_towire(&name, cctx, target, NULL));
180 
181 	return mem_tobuffer(target, sr.base, sr.length);
182 }
183 
184 static int
185 compare_nxt(ARGS_COMPARE) {
186 	isc_region_t r1;
187 	isc_region_t r2;
188 	dns_name_t name1;
189 	dns_name_t name2;
190 	int order;
191 
192 	REQUIRE(rdata1->type == rdata2->type);
193 	REQUIRE(rdata1->rdclass == rdata2->rdclass);
194 	REQUIRE(rdata1->type == dns_rdatatype_nxt);
195 	REQUIRE(rdata1->length != 0);
196 	REQUIRE(rdata2->length != 0);
197 
198 	dns_name_init(&name1, NULL);
199 	dns_name_init(&name2, NULL);
200 	dns_rdata_toregion(rdata1, &r1);
201 	dns_rdata_toregion(rdata2, &r2);
202 	dns_name_fromregion(&name1, &r1);
203 	dns_name_fromregion(&name2, &r2);
204 	order = dns_name_rdatacompare(&name1, &name2);
205 	if (order != 0) {
206 		return order;
207 	}
208 
209 	isc_region_consume(&r1, name_length(&name1));
210 	isc_region_consume(&r2, name_length(&name2));
211 
212 	return isc_region_compare(&r1, &r2);
213 }
214 
215 static isc_result_t
216 fromstruct_nxt(ARGS_FROMSTRUCT) {
217 	dns_rdata_nxt_t *nxt = source;
218 	isc_region_t region;
219 
220 	REQUIRE(type == dns_rdatatype_nxt);
221 	REQUIRE(nxt != NULL);
222 	REQUIRE(nxt->common.rdtype == type);
223 	REQUIRE(nxt->common.rdclass == rdclass);
224 	REQUIRE(nxt->typebits != NULL || nxt->len == 0);
225 	if (nxt->typebits != NULL && (nxt->typebits[0] & 0x80) == 0) {
226 		REQUIRE(nxt->len <= 16);
227 		REQUIRE(nxt->typebits[nxt->len - 1] != 0);
228 	}
229 
230 	UNUSED(type);
231 	UNUSED(rdclass);
232 
233 	dns_name_toregion(&nxt->next, &region);
234 	RETERR(isc_buffer_copyregion(target, &region));
235 
236 	return mem_tobuffer(target, nxt->typebits, nxt->len);
237 }
238 
239 static isc_result_t
240 tostruct_nxt(ARGS_TOSTRUCT) {
241 	isc_region_t region;
242 	dns_rdata_nxt_t *nxt = target;
243 	dns_name_t name;
244 
245 	REQUIRE(rdata->type == dns_rdatatype_nxt);
246 	REQUIRE(nxt != NULL);
247 	REQUIRE(rdata->length != 0);
248 
249 	nxt->common.rdclass = rdata->rdclass;
250 	nxt->common.rdtype = rdata->type;
251 	ISC_LINK_INIT(&nxt->common, link);
252 
253 	dns_name_init(&name, NULL);
254 	dns_rdata_toregion(rdata, &region);
255 	dns_name_fromregion(&name, &region);
256 	isc_region_consume(&region, name_length(&name));
257 	dns_name_init(&nxt->next, NULL);
258 	name_duporclone(&name, mctx, &nxt->next);
259 
260 	nxt->len = region.length;
261 	nxt->typebits = mem_maybedup(mctx, region.base, region.length);
262 	nxt->mctx = mctx;
263 	return ISC_R_SUCCESS;
264 }
265 
266 static void
267 freestruct_nxt(ARGS_FREESTRUCT) {
268 	dns_rdata_nxt_t *nxt = source;
269 
270 	REQUIRE(nxt != NULL);
271 	REQUIRE(nxt->common.rdtype == dns_rdatatype_nxt);
272 
273 	if (nxt->mctx == NULL) {
274 		return;
275 	}
276 
277 	dns_name_free(&nxt->next, nxt->mctx);
278 	if (nxt->typebits != NULL) {
279 		isc_mem_free(nxt->mctx, nxt->typebits);
280 	}
281 	nxt->mctx = NULL;
282 }
283 
284 static isc_result_t
285 additionaldata_nxt(ARGS_ADDLDATA) {
286 	REQUIRE(rdata->type == dns_rdatatype_nxt);
287 
288 	UNUSED(rdata);
289 	UNUSED(owner);
290 	UNUSED(add);
291 	UNUSED(arg);
292 
293 	return ISC_R_SUCCESS;
294 }
295 
296 static isc_result_t
297 digest_nxt(ARGS_DIGEST) {
298 	isc_region_t r;
299 	dns_name_t name;
300 	isc_result_t result;
301 
302 	REQUIRE(rdata->type == dns_rdatatype_nxt);
303 
304 	dns_rdata_toregion(rdata, &r);
305 	dns_name_init(&name, NULL);
306 	dns_name_fromregion(&name, &r);
307 	result = dns_name_digest(&name, digest, arg);
308 	if (result != ISC_R_SUCCESS) {
309 		return result;
310 	}
311 	isc_region_consume(&r, name_length(&name));
312 
313 	return (digest)(arg, &r);
314 }
315 
316 static bool
317 checkowner_nxt(ARGS_CHECKOWNER) {
318 	REQUIRE(type == dns_rdatatype_nxt);
319 
320 	UNUSED(name);
321 	UNUSED(type);
322 	UNUSED(rdclass);
323 	UNUSED(wildcard);
324 
325 	return true;
326 }
327 
328 static bool
329 checknames_nxt(ARGS_CHECKNAMES) {
330 	REQUIRE(rdata->type == dns_rdatatype_nxt);
331 
332 	UNUSED(rdata);
333 	UNUSED(owner);
334 	UNUSED(bad);
335 
336 	return true;
337 }
338 
339 static int
340 casecompare_nxt(ARGS_COMPARE) {
341 	return compare_nxt(rdata1, rdata2);
342 }
343 #endif /* RDATA_GENERIC_NXT_30_C */
344