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