1 /* $NetBSD: nxt_30.c,v 1.1 2024/02/18 20:57:43 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
fromtext_nxt(ARGS_FROMTEXT)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
totext_nxt(ARGS_TOTEXT)94 totext_nxt(ARGS_TOTEXT) {
95 isc_region_t sr;
96 unsigned int i, j;
97 dns_name_t name;
98 dns_name_t prefix;
99 bool sub;
100
101 REQUIRE(rdata->type == dns_rdatatype_nxt);
102 REQUIRE(rdata->length != 0);
103
104 dns_name_init(&name, NULL);
105 dns_name_init(&prefix, NULL);
106 dns_rdata_toregion(rdata, &sr);
107 dns_name_fromregion(&name, &sr);
108 isc_region_consume(&sr, name_length(&name));
109 sub = name_prefix(&name, tctx->origin, &prefix);
110 RETERR(dns_name_totext(&prefix, sub, 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
fromwire_nxt(ARGS_FROMWIRE)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 dns_decompress_setmethods(dctx, DNS_COMPRESS_NONE);
150
151 dns_name_init(&name, NULL);
152 RETERR(dns_name_fromwire(&name, source, dctx, options, 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
towire_nxt(ARGS_TOWIRE)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_setmethods(cctx, DNS_COMPRESS_NONE);
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));
180
181 return (mem_tobuffer(target, sr.base, sr.length));
182 }
183
184 static int
compare_nxt(ARGS_COMPARE)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
fromstruct_nxt(ARGS_FROMSTRUCT)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, ®ion);
234 RETERR(isc_buffer_copyregion(target, ®ion));
235
236 return (mem_tobuffer(target, nxt->typebits, nxt->len));
237 }
238
239 static isc_result_t
tostruct_nxt(ARGS_TOSTRUCT)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, ®ion);
255 dns_name_fromregion(&name, ®ion);
256 isc_region_consume(®ion, name_length(&name));
257 dns_name_init(&nxt->next, NULL);
258 RETERR(name_duporclone(&name, mctx, &nxt->next));
259
260 nxt->len = region.length;
261 nxt->typebits = mem_maybedup(mctx, region.base, region.length);
262 if (nxt->typebits == NULL) {
263 goto cleanup;
264 }
265
266 nxt->mctx = mctx;
267 return (ISC_R_SUCCESS);
268
269 cleanup:
270 if (mctx != NULL) {
271 dns_name_free(&nxt->next, mctx);
272 }
273 return (ISC_R_NOMEMORY);
274 }
275
276 static void
freestruct_nxt(ARGS_FREESTRUCT)277 freestruct_nxt(ARGS_FREESTRUCT) {
278 dns_rdata_nxt_t *nxt = source;
279
280 REQUIRE(nxt != NULL);
281 REQUIRE(nxt->common.rdtype == dns_rdatatype_nxt);
282
283 if (nxt->mctx == NULL) {
284 return;
285 }
286
287 dns_name_free(&nxt->next, nxt->mctx);
288 if (nxt->typebits != NULL) {
289 isc_mem_free(nxt->mctx, nxt->typebits);
290 }
291 nxt->mctx = NULL;
292 }
293
294 static isc_result_t
additionaldata_nxt(ARGS_ADDLDATA)295 additionaldata_nxt(ARGS_ADDLDATA) {
296 REQUIRE(rdata->type == dns_rdatatype_nxt);
297
298 UNUSED(rdata);
299 UNUSED(add);
300 UNUSED(arg);
301
302 return (ISC_R_SUCCESS);
303 }
304
305 static isc_result_t
digest_nxt(ARGS_DIGEST)306 digest_nxt(ARGS_DIGEST) {
307 isc_region_t r;
308 dns_name_t name;
309 isc_result_t result;
310
311 REQUIRE(rdata->type == dns_rdatatype_nxt);
312
313 dns_rdata_toregion(rdata, &r);
314 dns_name_init(&name, NULL);
315 dns_name_fromregion(&name, &r);
316 result = dns_name_digest(&name, digest, arg);
317 if (result != ISC_R_SUCCESS) {
318 return (result);
319 }
320 isc_region_consume(&r, name_length(&name));
321
322 return ((digest)(arg, &r));
323 }
324
325 static bool
checkowner_nxt(ARGS_CHECKOWNER)326 checkowner_nxt(ARGS_CHECKOWNER) {
327 REQUIRE(type == dns_rdatatype_nxt);
328
329 UNUSED(name);
330 UNUSED(type);
331 UNUSED(rdclass);
332 UNUSED(wildcard);
333
334 return (true);
335 }
336
337 static bool
checknames_nxt(ARGS_CHECKNAMES)338 checknames_nxt(ARGS_CHECKNAMES) {
339 REQUIRE(rdata->type == dns_rdatatype_nxt);
340
341 UNUSED(rdata);
342 UNUSED(owner);
343 UNUSED(bad);
344
345 return (true);
346 }
347
348 static int
casecompare_nxt(ARGS_COMPARE)349 casecompare_nxt(ARGS_COMPARE) {
350 return (compare_nxt(rdata1, rdata2));
351 }
352 #endif /* RDATA_GENERIC_NXT_30_C */
353