1/* 2 * Copyright (C) 2009, 2011 Internet Systems Consortium, Inc. ("ISC") 3 * 4 * Permission to use, copy, modify, and/or distribute this software for any 5 * purpose with or without fee is hereby granted, provided that the above 6 * copyright notice and this permission notice appear in all copies. 7 * 8 * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH 9 * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY 10 * AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT, 11 * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM 12 * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE 13 * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR 14 * PERFORMANCE OF THIS SOFTWARE. 15 */ 16 17/* $Id: hip_55.c,v 1.8 2011/01/13 04:59:26 tbox Exp $ */ 18 19/* reviewed: TBC */ 20 21/* RFC 5205 */ 22 23#ifndef RDATA_GENERIC_HIP_5_C 24#define RDATA_GENERIC_HIP_5_C 25 26#define RRTYPE_HIP_ATTRIBUTES (0) 27 28static inline isc_result_t 29fromtext_hip(ARGS_FROMTEXT) { 30 isc_token_t token; 31 dns_name_t name; 32 isc_buffer_t buffer; 33 isc_buffer_t hit_len; 34 isc_buffer_t key_len; 35 unsigned char *start; 36 size_t len; 37 38 REQUIRE(type == 55); 39 40 UNUSED(type); 41 UNUSED(rdclass); 42 UNUSED(callbacks); 43 44 /* 45 * Dummy HIT len. 46 */ 47 hit_len = *target; 48 RETERR(uint8_tobuffer(0, target)); 49 50 /* 51 * Algorithm. 52 */ 53 RETERR(isc_lex_getmastertoken(lexer, &token, isc_tokentype_number, 54 ISC_FALSE)); 55 if (token.value.as_ulong > 0xffU) 56 RETTOK(ISC_R_RANGE); 57 RETERR(uint8_tobuffer(token.value.as_ulong, target)); 58 59 /* 60 * Dummy KEY len. 61 */ 62 key_len = *target; 63 RETERR(uint16_tobuffer(0, target)); 64 65 /* 66 * HIT (base16). 67 */ 68 start = isc_buffer_used(target); 69 RETERR(isc_lex_getmastertoken(lexer, &token, isc_tokentype_string, 70 ISC_FALSE)); 71 RETTOK(isc_hex_decodestring(DNS_AS_STR(token), target)); 72 73 /* 74 * Fill in HIT len. 75 */ 76 len = (unsigned char *)isc_buffer_used(target) - start; 77 if (len > 0xffU) 78 RETTOK(ISC_R_RANGE); 79 RETERR(uint8_tobuffer(len, &hit_len)); 80 81 /* 82 * Public key (base64). 83 */ 84 start = isc_buffer_used(target); 85 RETERR(isc_lex_getmastertoken(lexer, &token, isc_tokentype_string, 86 ISC_FALSE)); 87 RETTOK(isc_base64_decodestring(DNS_AS_STR(token), target)); 88 89 /* 90 * Fill in KEY len. 91 */ 92 len = (unsigned char *)isc_buffer_used(target) - start; 93 if (len > 0xffffU) 94 RETTOK(ISC_R_RANGE); 95 RETERR(uint16_tobuffer(len, &key_len)); 96 97 /* 98 * Rendezvous Servers. 99 */ 100 dns_name_init(&name, NULL); 101 do { 102 RETERR(isc_lex_getmastertoken(lexer, &token, 103 isc_tokentype_string, 104 ISC_TRUE)); 105 if (token.type != isc_tokentype_string) 106 break; 107 buffer_fromregion(&buffer, &token.value.as_region); 108 origin = (origin != NULL) ? origin : dns_rootname; 109 RETTOK(dns_name_fromtext(&name, &buffer, origin, options, 110 target)); 111 } while (1); 112 113 /* 114 * Let upper layer handle eol/eof. 115 */ 116 isc_lex_ungettoken(lexer, &token); 117 118 return (ISC_R_SUCCESS); 119} 120 121static inline isc_result_t 122totext_hip(ARGS_TOTEXT) { 123 isc_region_t region; 124 dns_name_t name; 125 size_t length, key_len, hit_len; 126 unsigned char algorithm; 127 char buf[sizeof("225 ")]; 128 129 REQUIRE(rdata->type == 55); 130 REQUIRE(rdata->length != 0); 131 132 dns_rdata_toregion(rdata, ®ion); 133 134 hit_len = uint8_fromregion(®ion); 135 isc_region_consume(®ion, 1); 136 137 algorithm = uint8_fromregion(®ion); 138 isc_region_consume(®ion, 1); 139 140 key_len = uint16_fromregion(®ion); 141 isc_region_consume(®ion, 2); 142 143 if ((tctx->flags & DNS_STYLEFLAG_MULTILINE) != 0) 144 RETERR(str_totext("( ", target)); 145 146 /* 147 * Algorithm 148 */ 149 sprintf(buf, "%u ", algorithm); 150 RETERR(str_totext(buf, target)); 151 152 /* 153 * HIT. 154 */ 155 INSIST(hit_len < region.length); 156 length = region.length; 157 region.length = hit_len; 158 RETERR(isc_hex_totext(®ion, 1, "", target)); 159 region.length = length - hit_len; 160 RETERR(str_totext(tctx->linebreak, target)); 161 162 /* 163 * Public KEY. 164 */ 165 INSIST(key_len <= region.length); 166 length = region.length; 167 region.length = key_len; 168 RETERR(isc_base64_totext(®ion, 1, "", target)); 169 region.length = length - key_len; 170 RETERR(str_totext(tctx->linebreak, target)); 171 172 /* 173 * Rendezvous Servers. 174 */ 175 dns_name_init(&name, NULL); 176 while (region.length > 0) { 177 dns_name_fromregion(&name, ®ion); 178 179 RETERR(dns_name_totext(&name, ISC_FALSE, target)); 180 isc_region_consume(®ion, name.length); 181 if (region.length > 0) 182 RETERR(str_totext(tctx->linebreak, target)); 183 } 184 if ((tctx->flags & DNS_STYLEFLAG_MULTILINE) != 0) 185 RETERR(str_totext(" )", target)); 186 return (ISC_R_SUCCESS); 187} 188 189static inline isc_result_t 190fromwire_hip(ARGS_FROMWIRE) { 191 isc_region_t region, rr; 192 dns_name_t name; 193 isc_uint8_t hit_len; 194 isc_uint16_t key_len; 195 196 REQUIRE(type == 55); 197 198 UNUSED(type); 199 UNUSED(rdclass); 200 201 isc_buffer_activeregion(source, ®ion); 202 if (region.length < 4U) 203 RETERR(DNS_R_FORMERR); 204 205 rr = region; 206 hit_len = uint8_fromregion(®ion); 207 if (hit_len == 0) 208 RETERR(DNS_R_FORMERR); 209 isc_region_consume(®ion, 2); /* hit length + algorithm */ 210 key_len = uint16_fromregion(®ion); 211 if (key_len == 0) 212 RETERR(DNS_R_FORMERR); 213 isc_region_consume(®ion, 2); 214 if (region.length < (unsigned) (hit_len + key_len)) 215 RETERR(DNS_R_FORMERR); 216 217 RETERR(mem_tobuffer(target, rr.base, 4 + hit_len + key_len)); 218 isc_buffer_forward(source, 4 + hit_len + key_len); 219 220 dns_decompress_setmethods(dctx, DNS_COMPRESS_NONE); 221 while (isc_buffer_activelength(source) > 0) { 222 dns_name_init(&name, NULL); 223 RETERR(dns_name_fromwire(&name, source, dctx, options, target)); 224 } 225 return (ISC_R_SUCCESS); 226} 227 228static inline isc_result_t 229towire_hip(ARGS_TOWIRE) { 230 isc_region_t region; 231 232 REQUIRE(rdata->type == 55); 233 REQUIRE(rdata->length != 0); 234 235 UNUSED(cctx); 236 237 dns_rdata_toregion(rdata, ®ion); 238 return (mem_tobuffer(target, region.base, region.length)); 239} 240 241static inline int 242compare_hip(ARGS_COMPARE) { 243 isc_region_t region1; 244 isc_region_t region2; 245 246 REQUIRE(rdata1->type == rdata2->type); 247 REQUIRE(rdata1->rdclass == rdata2->rdclass); 248 REQUIRE(rdata1->type == 55); 249 REQUIRE(rdata1->length != 0); 250 REQUIRE(rdata2->length != 0); 251 252 dns_rdata_toregion(rdata1, ®ion1); 253 dns_rdata_toregion(rdata2, ®ion2); 254 return (isc_region_compare(®ion1, ®ion2)); 255} 256 257static inline isc_result_t 258fromstruct_hip(ARGS_FROMSTRUCT) { 259 dns_rdata_hip_t *hip = source; 260 dns_rdata_hip_t myhip; 261 isc_result_t result; 262 263 REQUIRE(type == 55); 264 REQUIRE(source != NULL); 265 REQUIRE(hip->common.rdtype == type); 266 REQUIRE(hip->common.rdclass == rdclass); 267 REQUIRE(hip->hit_len > 0 && hip->hit != NULL); 268 REQUIRE(hip->key_len > 0 && hip->key != NULL); 269 REQUIRE((hip->servers == NULL && hip->servers_len == 0) || 270 (hip->servers != NULL && hip->servers_len != 0)); 271 272 UNUSED(type); 273 UNUSED(rdclass); 274 275 RETERR(uint8_tobuffer(hip->hit_len, target)); 276 RETERR(uint8_tobuffer(hip->algorithm, target)); 277 RETERR(uint16_tobuffer(hip->key_len, target)); 278 RETERR(mem_tobuffer(target, hip->hit, hip->hit_len)); 279 RETERR(mem_tobuffer(target, hip->key, hip->key_len)); 280 281 myhip = *hip; 282 for (result = dns_rdata_hip_first(&myhip); 283 result == ISC_R_SUCCESS; 284 result = dns_rdata_hip_next(&myhip)) 285 /* empty */; 286 287 return(mem_tobuffer(target, hip->servers, hip->servers_len)); 288} 289 290static inline isc_result_t 291tostruct_hip(ARGS_TOSTRUCT) { 292 isc_region_t region; 293 dns_rdata_hip_t *hip = target; 294 295 REQUIRE(rdata->type == 55); 296 REQUIRE(target != NULL); 297 REQUIRE(rdata->length != 0); 298 299 hip->common.rdclass = rdata->rdclass; 300 hip->common.rdtype = rdata->type; 301 ISC_LINK_INIT(&hip->common, link); 302 303 dns_rdata_toregion(rdata, ®ion); 304 305 hip->hit_len = uint8_fromregion(®ion); 306 isc_region_consume(®ion, 1); 307 308 hip->algorithm = uint8_fromregion(®ion); 309 isc_region_consume(®ion, 1); 310 311 hip->key_len = uint16_fromregion(®ion); 312 isc_region_consume(®ion, 2); 313 314 hip->hit = hip->key = hip->servers = NULL; 315 316 hip->hit = mem_maybedup(mctx, region.base, hip->hit_len); 317 if (hip->hit == NULL) 318 goto cleanup; 319 isc_region_consume(®ion, hip->hit_len); 320 321 hip->key = mem_maybedup(mctx, region.base, hip->key_len); 322 if (hip->key == NULL) 323 goto cleanup; 324 isc_region_consume(®ion, hip->key_len); 325 326 hip->servers_len = region.length; 327 if (hip->servers_len != 0) { 328 hip->servers = mem_maybedup(mctx, region.base, region.length); 329 if (hip->servers == NULL) 330 goto cleanup; 331 } 332 333 hip->offset = hip->servers_len; 334 hip->mctx = mctx; 335 return (ISC_R_SUCCESS); 336 337 cleanup: 338 if (hip->hit != NULL) 339 isc_mem_free(mctx, hip->hit); 340 if (hip->key != NULL) 341 isc_mem_free(mctx, hip->key); 342 if (hip->servers != NULL) 343 isc_mem_free(mctx, hip->servers); 344 return (ISC_R_NOMEMORY); 345 346} 347 348static inline void 349freestruct_hip(ARGS_FREESTRUCT) { 350 dns_rdata_hip_t *hip = source; 351 352 REQUIRE(source != NULL); 353 354 if (hip->mctx == NULL) 355 return; 356 357 isc_mem_free(hip->mctx, hip->hit); 358 isc_mem_free(hip->mctx, hip->key); 359 if (hip->servers != NULL) 360 isc_mem_free(hip->mctx, hip->servers); 361 hip->mctx = NULL; 362} 363 364static inline isc_result_t 365additionaldata_hip(ARGS_ADDLDATA) { 366 UNUSED(rdata); 367 UNUSED(add); 368 UNUSED(arg); 369 370 REQUIRE(rdata->type == 55); 371 372 return (ISC_R_SUCCESS); 373} 374 375static inline isc_result_t 376digest_hip(ARGS_DIGEST) { 377 isc_region_t r; 378 379 REQUIRE(rdata->type == 55); 380 381 dns_rdata_toregion(rdata, &r); 382 return ((digest)(arg, &r)); 383} 384 385static inline isc_boolean_t 386checkowner_hip(ARGS_CHECKOWNER) { 387 388 REQUIRE(type == 55); 389 390 UNUSED(name); 391 UNUSED(type); 392 UNUSED(rdclass); 393 UNUSED(wildcard); 394 395 return (ISC_TRUE); 396} 397 398static inline isc_boolean_t 399checknames_hip(ARGS_CHECKNAMES) { 400 401 REQUIRE(rdata->type == 55); 402 403 UNUSED(rdata); 404 UNUSED(owner); 405 UNUSED(bad); 406 407 return (ISC_TRUE); 408} 409 410isc_result_t 411dns_rdata_hip_first(dns_rdata_hip_t *hip) { 412 if (hip->servers_len == 0) 413 return (ISC_R_NOMORE); 414 hip->offset = 0; 415 return (ISC_R_SUCCESS); 416} 417 418isc_result_t 419dns_rdata_hip_next(dns_rdata_hip_t *hip) { 420 isc_region_t region; 421 dns_name_t name; 422 423 if (hip->offset >= hip->servers_len) 424 return (ISC_R_NOMORE); 425 426 region.base = hip->servers + hip->offset; 427 region.length = hip->servers_len - hip->offset; 428 dns_name_init(&name, NULL); 429 dns_name_fromregion(&name, ®ion); 430 hip->offset += name.length; 431 INSIST(hip->offset <= hip->servers_len); 432 return (ISC_R_SUCCESS); 433} 434 435void 436dns_rdata_hip_current(dns_rdata_hip_t *hip, dns_name_t *name) { 437 isc_region_t region; 438 439 REQUIRE(hip->offset < hip->servers_len); 440 441 region.base = hip->servers + hip->offset; 442 region.length = hip->servers_len - hip->offset; 443 dns_name_fromregion(name, ®ion); 444 445 INSIST(name->length + hip->offset <= hip->servers_len); 446} 447 448static inline int 449casecompare_hip(ARGS_COMPARE) { 450 isc_region_t r1; 451 isc_region_t r2; 452 dns_name_t name1; 453 dns_name_t name2; 454 int order; 455 isc_uint8_t hit_len; 456 isc_uint16_t key_len; 457 458 REQUIRE(rdata1->type == rdata2->type); 459 REQUIRE(rdata1->rdclass == rdata2->rdclass); 460 REQUIRE(rdata1->type == 55); 461 REQUIRE(rdata1->length != 0); 462 REQUIRE(rdata2->length != 0); 463 464 dns_rdata_toregion(rdata1, &r1); 465 dns_rdata_toregion(rdata2, &r2); 466 467 INSIST(r1.length > 4); 468 INSIST(r2.length > 4); 469 r1.length = 4; 470 r2.length = 4; 471 order = isc_region_compare(&r1, &r2); 472 if (order != 0) 473 return (order); 474 475 hit_len = uint8_fromregion(&r1); 476 isc_region_consume(&r1, 2); /* hit length + algorithm */ 477 key_len = uint16_fromregion(&r1); 478 479 dns_rdata_toregion(rdata1, &r1); 480 dns_rdata_toregion(rdata2, &r2); 481 isc_region_consume(&r1, 4); 482 isc_region_consume(&r2, 4); 483 INSIST(r1.length >= (unsigned) (hit_len + key_len)); 484 INSIST(r2.length >= (unsigned) (hit_len + key_len)); 485 order = isc_region_compare(&r1, &r2); 486 if (order != 0) 487 return (order); 488 isc_region_consume(&r1, hit_len + key_len); 489 isc_region_consume(&r2, hit_len + key_len); 490 491 dns_name_init(&name1, NULL); 492 dns_name_init(&name2, NULL); 493 while (r1.length != 0 && r2.length != 0) { 494 dns_name_fromregion(&name1, &r1); 495 dns_name_fromregion(&name2, &r2); 496 order = dns_name_rdatacompare(&name1, &name2); 497 if (order != 0) 498 return (order); 499 500 isc_region_consume(&r1, name_length(&name1)); 501 isc_region_consume(&r2, name_length(&name2)); 502 } 503 return (isc_region_compare(&r1, &r2)); 504} 505 506#endif /* RDATA_GENERIC_HIP_5_C */ 507