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