1 /* $NetBSD: opt_41.c,v 1.8 2015/07/08 17:28:59 christos Exp $ */ 2 3 /* 4 * Copyright (C) 2004, 2005, 2007, 2009, 2011-2014 Internet Systems Consortium, Inc. ("ISC") 5 * Copyright (C) 1998-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 */ 21 22 /* Reviewed: Thu Mar 16 14:06:44 PST 2000 by gson */ 23 24 /* RFC2671 */ 25 26 #ifndef RDATA_GENERIC_OPT_41_C 27 #define RDATA_GENERIC_OPT_41_C 28 29 #define RRTYPE_OPT_ATTRIBUTES (DNS_RDATATYPEATTR_SINGLETON | \ 30 DNS_RDATATYPEATTR_META | \ 31 DNS_RDATATYPEATTR_NOTQUESTION) 32 33 static inline isc_result_t 34 fromtext_opt(ARGS_FROMTEXT) { 35 /* 36 * OPT records do not have a text format. 37 */ 38 39 REQUIRE(type == 41); 40 41 UNUSED(type); 42 UNUSED(rdclass); 43 UNUSED(lexer); 44 UNUSED(origin); 45 UNUSED(options); 46 UNUSED(target); 47 UNUSED(callbacks); 48 49 return (ISC_R_NOTIMPLEMENTED); 50 } 51 52 static inline isc_result_t 53 totext_opt(ARGS_TOTEXT) { 54 isc_region_t r; 55 isc_region_t or; 56 isc_uint16_t option; 57 isc_uint16_t length; 58 char buf[sizeof("64000 64000")]; 59 60 /* 61 * OPT records do not have a text format. 62 */ 63 64 REQUIRE(rdata->type == 41); 65 66 dns_rdata_toregion(rdata, &r); 67 while (r.length > 0) { 68 option = uint16_fromregion(&r); 69 isc_region_consume(&r, 2); 70 length = uint16_fromregion(&r); 71 isc_region_consume(&r, 2); 72 sprintf(buf, "%u %u", option, length); 73 RETERR(str_totext(buf, target)); 74 INSIST(r.length >= length); 75 if (length > 0) { 76 if ((tctx->flags & DNS_STYLEFLAG_MULTILINE) != 0) 77 RETERR(str_totext(" (", target)); 78 RETERR(str_totext(tctx->linebreak, target)); 79 or = r; 80 or.length = length; 81 if (tctx->width == 0) /* No splitting */ 82 RETERR(isc_base64_totext(&or, 60, "", target)); 83 else 84 RETERR(isc_base64_totext(&or, tctx->width - 2, 85 tctx->linebreak, 86 target)); 87 isc_region_consume(&r, length); 88 if ((tctx->flags & DNS_STYLEFLAG_MULTILINE) != 0) 89 RETERR(str_totext(" )", target)); 90 } 91 if (r.length > 0) 92 RETERR(str_totext(" ", target)); 93 } 94 95 return (ISC_R_SUCCESS); 96 } 97 98 static inline isc_result_t 99 fromwire_opt(ARGS_FROMWIRE) { 100 isc_region_t sregion; 101 isc_region_t tregion; 102 isc_uint16_t opt; 103 isc_uint16_t length; 104 unsigned int total; 105 106 REQUIRE(type == 41); 107 108 UNUSED(type); 109 UNUSED(rdclass); 110 UNUSED(dctx); 111 UNUSED(options); 112 113 isc_buffer_activeregion(source, &sregion); 114 total = 0; 115 while (sregion.length != 0) { 116 if (sregion.length < 4) 117 return (ISC_R_UNEXPECTEDEND); 118 opt = uint16_fromregion(&sregion); 119 isc_region_consume(&sregion, 2); 120 length = uint16_fromregion(&sregion); 121 isc_region_consume(&sregion, 2); 122 total += 4; 123 if (sregion.length < length) 124 return (ISC_R_UNEXPECTEDEND); 125 switch (opt) { 126 case DNS_OPT_CLIENT_SUBNET: { 127 isc_uint16_t family; 128 isc_uint8_t addrlen; 129 isc_uint8_t scope; 130 isc_uint8_t addrbytes; 131 132 if (length < 4) 133 return (DNS_R_FORMERR); 134 family = uint16_fromregion(&sregion); 135 isc_region_consume(&sregion, 2); 136 addrlen = uint8_fromregion(&sregion); 137 isc_region_consume(&sregion, 1); 138 scope = uint8_fromregion(&sregion); 139 isc_region_consume(&sregion, 1); 140 switch (family) { 141 case 1: 142 if (addrlen > 32U || scope > 32U) 143 return (DNS_R_FORMERR); 144 break; 145 case 2: 146 if (addrlen > 128U || scope > 128U) 147 return (DNS_R_FORMERR); 148 break; 149 } 150 addrbytes = (addrlen + 7) / 8; 151 if (addrbytes + 4 != length) 152 return (DNS_R_FORMERR); 153 isc_region_consume(&sregion, addrbytes); 154 break; 155 } 156 case DNS_OPT_EXPIRE: 157 /* 158 * Request has zero length. Response is 32 bits. 159 */ 160 if (length != 0 && length != 4) 161 return (DNS_R_FORMERR); 162 isc_region_consume(&sregion, length); 163 break; 164 default: 165 isc_region_consume(&sregion, length); 166 break; 167 } 168 total += length; 169 } 170 171 isc_buffer_activeregion(source, &sregion); 172 isc_buffer_availableregion(target, &tregion); 173 if (tregion.length < total) 174 return (ISC_R_NOSPACE); 175 memmove(tregion.base, sregion.base, total); 176 isc_buffer_forward(source, total); 177 isc_buffer_add(target, total); 178 179 return (ISC_R_SUCCESS); 180 } 181 182 static inline isc_result_t 183 towire_opt(ARGS_TOWIRE) { 184 185 REQUIRE(rdata->type == 41); 186 187 UNUSED(cctx); 188 189 return (mem_tobuffer(target, rdata->data, rdata->length)); 190 } 191 192 static inline int 193 compare_opt(ARGS_COMPARE) { 194 isc_region_t r1; 195 isc_region_t r2; 196 197 REQUIRE(rdata1->type == rdata2->type); 198 REQUIRE(rdata1->rdclass == rdata2->rdclass); 199 REQUIRE(rdata1->type == 41); 200 201 dns_rdata_toregion(rdata1, &r1); 202 dns_rdata_toregion(rdata2, &r2); 203 return (isc_region_compare(&r1, &r2)); 204 } 205 206 static inline isc_result_t 207 fromstruct_opt(ARGS_FROMSTRUCT) { 208 dns_rdata_opt_t *opt = source; 209 isc_region_t region; 210 isc_uint16_t length; 211 212 REQUIRE(type == 41); 213 REQUIRE(source != NULL); 214 REQUIRE(opt->common.rdtype == type); 215 REQUIRE(opt->common.rdclass == rdclass); 216 REQUIRE(opt->options != NULL || opt->length == 0); 217 218 UNUSED(type); 219 UNUSED(rdclass); 220 221 region.base = opt->options; 222 region.length = opt->length; 223 while (region.length >= 4) { 224 isc_region_consume(®ion, 2); /* opt */ 225 length = uint16_fromregion(®ion); 226 isc_region_consume(®ion, 2); 227 if (region.length < length) 228 return (ISC_R_UNEXPECTEDEND); 229 isc_region_consume(®ion, length); 230 } 231 if (region.length != 0) 232 return (ISC_R_UNEXPECTEDEND); 233 234 return (mem_tobuffer(target, opt->options, opt->length)); 235 } 236 237 static inline isc_result_t 238 tostruct_opt(ARGS_TOSTRUCT) { 239 dns_rdata_opt_t *opt = target; 240 isc_region_t r; 241 242 REQUIRE(rdata->type == 41); 243 REQUIRE(target != NULL); 244 245 opt->common.rdclass = rdata->rdclass; 246 opt->common.rdtype = rdata->type; 247 ISC_LINK_INIT(&opt->common, link); 248 249 dns_rdata_toregion(rdata, &r); 250 opt->length = r.length; 251 opt->options = mem_maybedup(mctx, r.base, r.length); 252 if (opt->options == NULL) 253 return (ISC_R_NOMEMORY); 254 255 opt->offset = 0; 256 opt->mctx = mctx; 257 return (ISC_R_SUCCESS); 258 } 259 260 static inline void 261 freestruct_opt(ARGS_FREESTRUCT) { 262 dns_rdata_opt_t *opt = source; 263 264 REQUIRE(source != NULL); 265 REQUIRE(opt->common.rdtype == 41); 266 267 if (opt->mctx == NULL) 268 return; 269 270 if (opt->options != NULL) 271 isc_mem_free(opt->mctx, opt->options); 272 opt->mctx = NULL; 273 } 274 275 static inline isc_result_t 276 additionaldata_opt(ARGS_ADDLDATA) { 277 REQUIRE(rdata->type == 41); 278 279 UNUSED(rdata); 280 UNUSED(add); 281 UNUSED(arg); 282 283 return (ISC_R_SUCCESS); 284 } 285 286 static inline isc_result_t 287 digest_opt(ARGS_DIGEST) { 288 289 /* 290 * OPT records are not digested. 291 */ 292 293 REQUIRE(rdata->type == 41); 294 295 UNUSED(rdata); 296 UNUSED(digest); 297 UNUSED(arg); 298 299 return (ISC_R_NOTIMPLEMENTED); 300 } 301 302 static inline isc_boolean_t 303 checkowner_opt(ARGS_CHECKOWNER) { 304 305 REQUIRE(type == 41); 306 307 UNUSED(type); 308 UNUSED(rdclass); 309 UNUSED(wildcard); 310 311 return (dns_name_equal(name, dns_rootname)); 312 } 313 314 static inline isc_boolean_t 315 checknames_opt(ARGS_CHECKNAMES) { 316 317 REQUIRE(rdata->type == 41); 318 319 UNUSED(rdata); 320 UNUSED(owner); 321 UNUSED(bad); 322 323 return (ISC_TRUE); 324 } 325 326 static inline int 327 casecompare_opt(ARGS_COMPARE) { 328 return (compare_opt(rdata1, rdata2)); 329 } 330 331 isc_result_t 332 dns_rdata_opt_first(dns_rdata_opt_t *opt) { 333 334 REQUIRE(opt != NULL); 335 REQUIRE(opt->common.rdtype == 41); 336 REQUIRE(opt->options != NULL || opt->length == 0); 337 338 if (opt->length == 0) 339 return (ISC_R_NOMORE); 340 341 opt->offset = 0; 342 return (ISC_R_SUCCESS); 343 } 344 345 isc_result_t 346 dns_rdata_opt_next(dns_rdata_opt_t *opt) { 347 isc_region_t r; 348 isc_uint16_t length; 349 350 REQUIRE(opt != NULL); 351 REQUIRE(opt->common.rdtype == 41); 352 REQUIRE(opt->options != NULL && opt->length != 0); 353 REQUIRE(opt->offset < opt->length); 354 355 INSIST(opt->offset + 4 <= opt->length); 356 r.base = opt->options + opt->offset + 2; 357 r.length = opt->length - opt->offset - 2; 358 length = uint16_fromregion(&r); 359 INSIST(opt->offset + 4 + length <= opt->length); 360 opt->offset = opt->offset + 4 + length; 361 if (opt->offset == opt->length) 362 return (ISC_R_NOMORE); 363 return (ISC_R_SUCCESS); 364 } 365 366 isc_result_t 367 dns_rdata_opt_current(dns_rdata_opt_t *opt, dns_rdata_opt_opcode_t *opcode) { 368 isc_region_t r; 369 370 REQUIRE(opt != NULL); 371 REQUIRE(opcode != NULL); 372 REQUIRE(opt->common.rdtype == 41); 373 REQUIRE(opt->options != NULL); 374 REQUIRE(opt->offset < opt->length); 375 376 INSIST(opt->offset + 4 <= opt->length); 377 r.base = opt->options + opt->offset; 378 r.length = opt->length - opt->offset; 379 380 opcode->opcode = uint16_fromregion(&r); 381 isc_region_consume(&r, 2); 382 opcode->length = uint16_fromregion(&r); 383 isc_region_consume(&r, 2); 384 opcode->data = r.base; 385 INSIST(opt->offset + 4 + opcode->length <= opt->length); 386 387 return (ISC_R_SUCCESS); 388 } 389 390 #endif /* RDATA_GENERIC_OPT_41_C */ 391