1 /* $NetBSD: apl_42.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 /* RFC3123 */
17
18 #ifndef RDATA_IN_1_APL_42_C
19 #define RDATA_IN_1_APL_42_C
20
21 #define RRTYPE_APL_ATTRIBUTES (0)
22
23 static isc_result_t
fromtext_in_apl(ARGS_FROMTEXT)24 fromtext_in_apl(ARGS_FROMTEXT) {
25 isc_token_t token;
26 unsigned char addr[16];
27 unsigned long afi;
28 uint8_t prefix;
29 uint8_t len;
30 bool neg;
31 char *cp, *ap, *slash;
32 int n;
33
34 REQUIRE(type == dns_rdatatype_apl);
35 REQUIRE(rdclass == dns_rdataclass_in);
36
37 UNUSED(type);
38 UNUSED(rdclass);
39 UNUSED(origin);
40 UNUSED(options);
41 UNUSED(callbacks);
42
43 do {
44 RETERR(isc_lex_getmastertoken(lexer, &token,
45 isc_tokentype_string, true));
46 if (token.type != isc_tokentype_string) {
47 break;
48 }
49
50 cp = DNS_AS_STR(token);
51 neg = (*cp == '!');
52 if (neg) {
53 cp++;
54 }
55 afi = strtoul(cp, &ap, 10);
56 if (*ap++ != ':' || cp == ap) {
57 RETTOK(DNS_R_SYNTAX);
58 }
59 if (afi > 0xffffU) {
60 RETTOK(ISC_R_RANGE);
61 }
62 slash = strchr(ap, '/');
63 if (slash == NULL || slash == ap) {
64 RETTOK(DNS_R_SYNTAX);
65 }
66 RETTOK(isc_parse_uint8(&prefix, slash + 1, 10));
67 switch (afi) {
68 case 1:
69 *slash = '\0';
70 n = inet_pton(AF_INET, ap, addr);
71 *slash = '/';
72 if (n != 1) {
73 RETTOK(DNS_R_BADDOTTEDQUAD);
74 }
75 if (prefix > 32) {
76 RETTOK(ISC_R_RANGE);
77 }
78 for (len = 4; len > 0; len--) {
79 if (addr[len - 1] != 0) {
80 break;
81 }
82 }
83 break;
84
85 case 2:
86 *slash = '\0';
87 n = inet_pton(AF_INET6, ap, addr);
88 *slash = '/';
89 if (n != 1) {
90 RETTOK(DNS_R_BADAAAA);
91 }
92 if (prefix > 128) {
93 RETTOK(ISC_R_RANGE);
94 }
95 for (len = 16; len > 0; len--) {
96 if (addr[len - 1] != 0) {
97 break;
98 }
99 }
100 break;
101
102 default:
103 RETTOK(ISC_R_NOTIMPLEMENTED);
104 }
105 RETERR(uint16_tobuffer(afi, target));
106 RETERR(uint8_tobuffer(prefix, target));
107 RETERR(uint8_tobuffer(len | ((neg) ? 0x80 : 0), target));
108 RETERR(mem_tobuffer(target, addr, len));
109 } while (1);
110
111 /*
112 * Let upper layer handle eol/eof.
113 */
114 isc_lex_ungettoken(lexer, &token);
115
116 return (ISC_R_SUCCESS);
117 }
118
119 static isc_result_t
totext_in_apl(ARGS_TOTEXT)120 totext_in_apl(ARGS_TOTEXT) {
121 isc_region_t sr;
122 isc_region_t ir;
123 uint16_t afi;
124 uint8_t prefix;
125 uint8_t len;
126 bool neg;
127 unsigned char buf[16];
128 char txt[sizeof(" !64000:")];
129 const char *sep = "";
130 int n;
131
132 REQUIRE(rdata->type == dns_rdatatype_apl);
133 REQUIRE(rdata->rdclass == dns_rdataclass_in);
134
135 UNUSED(tctx);
136
137 dns_rdata_toregion(rdata, &sr);
138 ir.base = buf;
139 ir.length = sizeof(buf);
140
141 while (sr.length > 0) {
142 INSIST(sr.length >= 4);
143 afi = uint16_fromregion(&sr);
144 isc_region_consume(&sr, 2);
145 prefix = *sr.base;
146 isc_region_consume(&sr, 1);
147 len = (*sr.base & 0x7f);
148 neg = (*sr.base & 0x80);
149 isc_region_consume(&sr, 1);
150 INSIST(len <= sr.length);
151 n = snprintf(txt, sizeof(txt), "%s%s%u:", sep, neg ? "!" : "",
152 afi);
153 INSIST(n < (int)sizeof(txt));
154 RETERR(str_totext(txt, target));
155 switch (afi) {
156 case 1:
157 INSIST(len <= 4);
158 INSIST(prefix <= 32);
159 memset(buf, 0, sizeof(buf));
160 memmove(buf, sr.base, len);
161 RETERR(inet_totext(AF_INET, tctx->flags, &ir, target));
162 break;
163
164 case 2:
165 INSIST(len <= 16);
166 INSIST(prefix <= 128);
167 memset(buf, 0, sizeof(buf));
168 memmove(buf, sr.base, len);
169 RETERR(inet_totext(AF_INET6, tctx->flags, &ir, target));
170 break;
171
172 default:
173 return (ISC_R_NOTIMPLEMENTED);
174 }
175 n = snprintf(txt, sizeof(txt), "/%u", prefix);
176 INSIST(n < (int)sizeof(txt));
177 RETERR(str_totext(txt, target));
178 isc_region_consume(&sr, len);
179 sep = " ";
180 }
181 return (ISC_R_SUCCESS);
182 }
183
184 static isc_result_t
fromwire_in_apl(ARGS_FROMWIRE)185 fromwire_in_apl(ARGS_FROMWIRE) {
186 isc_region_t sr, sr2;
187 isc_region_t tr;
188 uint16_t afi;
189 uint8_t prefix;
190 uint8_t len;
191
192 REQUIRE(type == dns_rdatatype_apl);
193 REQUIRE(rdclass == dns_rdataclass_in);
194
195 UNUSED(type);
196 UNUSED(dctx);
197 UNUSED(rdclass);
198 UNUSED(options);
199
200 isc_buffer_activeregion(source, &sr);
201 isc_buffer_availableregion(target, &tr);
202 if (sr.length > tr.length) {
203 return (ISC_R_NOSPACE);
204 }
205 sr2 = sr;
206
207 /* Zero or more items */
208 while (sr.length > 0) {
209 if (sr.length < 4) {
210 return (ISC_R_UNEXPECTEDEND);
211 }
212 afi = uint16_fromregion(&sr);
213 isc_region_consume(&sr, 2);
214 prefix = *sr.base;
215 isc_region_consume(&sr, 1);
216 len = (*sr.base & 0x7f);
217 isc_region_consume(&sr, 1);
218 if (len > sr.length) {
219 return (ISC_R_UNEXPECTEDEND);
220 }
221 switch (afi) {
222 case 1:
223 if (prefix > 32 || len > 4) {
224 return (ISC_R_RANGE);
225 }
226 break;
227 case 2:
228 if (prefix > 128 || len > 16) {
229 return (ISC_R_RANGE);
230 }
231 }
232 if (len > 0 && sr.base[len - 1] == 0) {
233 return (DNS_R_FORMERR);
234 }
235 isc_region_consume(&sr, len);
236 }
237 isc_buffer_forward(source, sr2.length);
238 return (mem_tobuffer(target, sr2.base, sr2.length));
239 }
240
241 static isc_result_t
towire_in_apl(ARGS_TOWIRE)242 towire_in_apl(ARGS_TOWIRE) {
243 UNUSED(cctx);
244
245 REQUIRE(rdata->type == dns_rdatatype_apl);
246 REQUIRE(rdata->rdclass == dns_rdataclass_in);
247
248 return (mem_tobuffer(target, rdata->data, rdata->length));
249 }
250
251 static int
compare_in_apl(ARGS_COMPARE)252 compare_in_apl(ARGS_COMPARE) {
253 isc_region_t r1;
254 isc_region_t r2;
255
256 REQUIRE(rdata1->type == rdata2->type);
257 REQUIRE(rdata1->rdclass == rdata2->rdclass);
258 REQUIRE(rdata1->type == dns_rdatatype_apl);
259 REQUIRE(rdata1->rdclass == dns_rdataclass_in);
260
261 dns_rdata_toregion(rdata1, &r1);
262 dns_rdata_toregion(rdata2, &r2);
263 return (isc_region_compare(&r1, &r2));
264 }
265
266 static isc_result_t
fromstruct_in_apl(ARGS_FROMSTRUCT)267 fromstruct_in_apl(ARGS_FROMSTRUCT) {
268 dns_rdata_in_apl_t *apl = source;
269 isc_buffer_t b;
270
271 REQUIRE(type == dns_rdatatype_apl);
272 REQUIRE(rdclass == dns_rdataclass_in);
273 REQUIRE(apl != NULL);
274 REQUIRE(apl->common.rdtype == type);
275 REQUIRE(apl->common.rdclass == rdclass);
276 REQUIRE(apl->apl != NULL || apl->apl_len == 0);
277
278 isc_buffer_init(&b, apl->apl, apl->apl_len);
279 isc_buffer_add(&b, apl->apl_len);
280 isc_buffer_setactive(&b, apl->apl_len);
281 return (fromwire_in_apl(rdclass, type, &b, NULL, false, target));
282 }
283
284 static isc_result_t
tostruct_in_apl(ARGS_TOSTRUCT)285 tostruct_in_apl(ARGS_TOSTRUCT) {
286 dns_rdata_in_apl_t *apl = target;
287 isc_region_t r;
288
289 REQUIRE(apl != NULL);
290 REQUIRE(rdata->type == dns_rdatatype_apl);
291 REQUIRE(rdata->rdclass == dns_rdataclass_in);
292
293 apl->common.rdclass = rdata->rdclass;
294 apl->common.rdtype = rdata->type;
295 ISC_LINK_INIT(&apl->common, link);
296
297 dns_rdata_toregion(rdata, &r);
298 apl->apl_len = r.length;
299 apl->apl = mem_maybedup(mctx, r.base, r.length);
300 if (apl->apl == NULL) {
301 return (ISC_R_NOMEMORY);
302 }
303
304 apl->offset = 0;
305 apl->mctx = mctx;
306 return (ISC_R_SUCCESS);
307 }
308
309 static void
freestruct_in_apl(ARGS_FREESTRUCT)310 freestruct_in_apl(ARGS_FREESTRUCT) {
311 dns_rdata_in_apl_t *apl = source;
312
313 REQUIRE(apl != NULL);
314 REQUIRE(apl->common.rdtype == dns_rdatatype_apl);
315 REQUIRE(apl->common.rdclass == dns_rdataclass_in);
316
317 if (apl->mctx == NULL) {
318 return;
319 }
320 if (apl->apl != NULL) {
321 isc_mem_free(apl->mctx, apl->apl);
322 }
323 apl->mctx = NULL;
324 }
325
326 isc_result_t
dns_rdata_apl_first(dns_rdata_in_apl_t * apl)327 dns_rdata_apl_first(dns_rdata_in_apl_t *apl) {
328 uint32_t length;
329
330 REQUIRE(apl != NULL);
331 REQUIRE(apl->common.rdtype == dns_rdatatype_apl);
332 REQUIRE(apl->common.rdclass == dns_rdataclass_in);
333 REQUIRE(apl->apl != NULL || apl->apl_len == 0);
334
335 /*
336 * If no APL return ISC_R_NOMORE.
337 */
338 if (apl->apl == NULL) {
339 return (ISC_R_NOMORE);
340 }
341
342 /*
343 * Sanity check data.
344 */
345 INSIST(apl->apl_len > 3U);
346 length = apl->apl[apl->offset + 3] & 0x7f;
347 INSIST(4 + length <= apl->apl_len);
348
349 apl->offset = 0;
350 return (ISC_R_SUCCESS);
351 }
352
353 isc_result_t
dns_rdata_apl_next(dns_rdata_in_apl_t * apl)354 dns_rdata_apl_next(dns_rdata_in_apl_t *apl) {
355 uint32_t length;
356
357 REQUIRE(apl != NULL);
358 REQUIRE(apl->common.rdtype == dns_rdatatype_apl);
359 REQUIRE(apl->common.rdclass == dns_rdataclass_in);
360 REQUIRE(apl->apl != NULL || apl->apl_len == 0);
361
362 /*
363 * No APL or have already reached the end return ISC_R_NOMORE.
364 */
365 if (apl->apl == NULL || apl->offset == apl->apl_len) {
366 return (ISC_R_NOMORE);
367 }
368
369 /*
370 * Sanity check data.
371 */
372 INSIST(apl->offset < apl->apl_len);
373 INSIST(apl->apl_len > 3U);
374 INSIST(apl->offset <= apl->apl_len - 4U);
375 length = apl->apl[apl->offset + 3] & 0x7f;
376 /*
377 * 16 to 32 bits promotion as 'length' is 32 bits so there is
378 * no overflow problems.
379 */
380 INSIST(4 + length + apl->offset <= apl->apl_len);
381
382 apl->offset += 4 + length;
383 return ((apl->offset < apl->apl_len) ? ISC_R_SUCCESS : ISC_R_NOMORE);
384 }
385
386 isc_result_t
dns_rdata_apl_current(dns_rdata_in_apl_t * apl,dns_rdata_apl_ent_t * ent)387 dns_rdata_apl_current(dns_rdata_in_apl_t *apl, dns_rdata_apl_ent_t *ent) {
388 uint32_t length;
389
390 REQUIRE(apl != NULL);
391 REQUIRE(apl->common.rdtype == dns_rdatatype_apl);
392 REQUIRE(apl->common.rdclass == dns_rdataclass_in);
393 REQUIRE(ent != NULL);
394 REQUIRE(apl->apl != NULL || apl->apl_len == 0);
395 REQUIRE(apl->offset <= apl->apl_len);
396
397 if (apl->offset == apl->apl_len) {
398 return (ISC_R_NOMORE);
399 }
400
401 /*
402 * Sanity check data.
403 */
404 INSIST(apl->apl_len > 3U);
405 INSIST(apl->offset <= apl->apl_len - 4U);
406 length = (apl->apl[apl->offset + 3] & 0x7f);
407 /*
408 * 16 to 32 bits promotion as 'length' is 32 bits so there is
409 * no overflow problems.
410 */
411 INSIST(4 + length + apl->offset <= apl->apl_len);
412
413 ent->family = (apl->apl[apl->offset] << 8) + apl->apl[apl->offset + 1];
414 ent->prefix = apl->apl[apl->offset + 2];
415 ent->length = length;
416 ent->negative = (apl->apl[apl->offset + 3] & 0x80);
417 if (ent->length != 0) {
418 ent->data = &apl->apl[apl->offset + 4];
419 } else {
420 ent->data = NULL;
421 }
422 return (ISC_R_SUCCESS);
423 }
424
425 unsigned int
dns_rdata_apl_count(const dns_rdata_in_apl_t * apl)426 dns_rdata_apl_count(const dns_rdata_in_apl_t *apl) {
427 return (apl->apl_len);
428 }
429
430 static isc_result_t
additionaldata_in_apl(ARGS_ADDLDATA)431 additionaldata_in_apl(ARGS_ADDLDATA) {
432 REQUIRE(rdata->type == dns_rdatatype_apl);
433 REQUIRE(rdata->rdclass == dns_rdataclass_in);
434
435 (void)add;
436 (void)arg;
437
438 return (ISC_R_SUCCESS);
439 }
440
441 static isc_result_t
digest_in_apl(ARGS_DIGEST)442 digest_in_apl(ARGS_DIGEST) {
443 isc_region_t r;
444
445 REQUIRE(rdata->type == dns_rdatatype_apl);
446 REQUIRE(rdata->rdclass == dns_rdataclass_in);
447
448 dns_rdata_toregion(rdata, &r);
449
450 return ((digest)(arg, &r));
451 }
452
453 static bool
checkowner_in_apl(ARGS_CHECKOWNER)454 checkowner_in_apl(ARGS_CHECKOWNER) {
455 REQUIRE(type == dns_rdatatype_apl);
456 REQUIRE(rdclass == dns_rdataclass_in);
457
458 UNUSED(name);
459 UNUSED(type);
460 UNUSED(rdclass);
461 UNUSED(wildcard);
462
463 return (true);
464 }
465
466 static bool
checknames_in_apl(ARGS_CHECKNAMES)467 checknames_in_apl(ARGS_CHECKNAMES) {
468 REQUIRE(rdata->type == dns_rdatatype_apl);
469 REQUIRE(rdata->rdclass == dns_rdataclass_in);
470
471 UNUSED(rdata);
472 UNUSED(owner);
473 UNUSED(bad);
474
475 return (true);
476 }
477
478 static int
casecompare_in_apl(ARGS_COMPARE)479 casecompare_in_apl(ARGS_COMPARE) {
480 return (compare_in_apl(rdata1, rdata2));
481 }
482
483 #endif /* RDATA_IN_1_APL_42_C */
484