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