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