1 /* $NetBSD: ipseckey_45.c,v 1.11 2025/01/26 16:25:31 christos Exp $ */ 2 3 /* 4 * Copyright (C) Internet Systems Consortium, Inc. ("ISC") 5 * 6 * SPDX-License-Identifier: MPL-2.0 7 * 8 * This Source Code Form is subject to the terms of the Mozilla Public 9 * License, v. 2.0. If a copy of the MPL was not distributed with this 10 * file, you can obtain one at https://mozilla.org/MPL/2.0/. 11 * 12 * See the COPYRIGHT file distributed with this work for additional 13 * information regarding copyright ownership. 14 */ 15 16 #ifndef RDATA_GENERIC_IPSECKEY_45_C 17 #define RDATA_GENERIC_IPSECKEY_45_C 18 19 #include <string.h> 20 21 #include <isc/net.h> 22 23 #define RRTYPE_IPSECKEY_ATTRIBUTES (0) 24 25 static isc_result_t 26 fromtext_ipseckey(ARGS_FROMTEXT) { 27 isc_token_t token; 28 dns_name_t name; 29 isc_buffer_t buffer; 30 unsigned int gateway; 31 struct in_addr addr; 32 unsigned char addr6[16]; 33 isc_region_t region; 34 35 REQUIRE(type == dns_rdatatype_ipseckey); 36 37 UNUSED(type); 38 UNUSED(rdclass); 39 UNUSED(callbacks); 40 41 /* 42 * Precedence. 43 */ 44 RETERR(isc_lex_getmastertoken(lexer, &token, isc_tokentype_number, 45 false)); 46 if (token.value.as_ulong > 0xffU) { 47 RETTOK(ISC_R_RANGE); 48 } 49 RETERR(uint8_tobuffer(token.value.as_ulong, target)); 50 51 /* 52 * Gateway type. 53 */ 54 RETERR(isc_lex_getmastertoken(lexer, &token, isc_tokentype_number, 55 false)); 56 if (token.value.as_ulong > 0x3U) { 57 RETTOK(ISC_R_RANGE); 58 } 59 RETERR(uint8_tobuffer(token.value.as_ulong, target)); 60 gateway = token.value.as_ulong; 61 62 /* 63 * Algorithm. 64 */ 65 RETERR(isc_lex_getmastertoken(lexer, &token, isc_tokentype_number, 66 false)); 67 if (token.value.as_ulong > 0xffU) { 68 RETTOK(ISC_R_RANGE); 69 } 70 RETERR(uint8_tobuffer(token.value.as_ulong, target)); 71 72 /* 73 * Gateway. 74 */ 75 RETERR(isc_lex_getmastertoken(lexer, &token, isc_tokentype_string, 76 false)); 77 78 switch (gateway) { 79 case 0: 80 if (strcmp(DNS_AS_STR(token), ".") != 0) { 81 RETTOK(DNS_R_SYNTAX); 82 } 83 break; 84 85 case 1: 86 if (inet_pton(AF_INET, DNS_AS_STR(token), &addr) != 1) { 87 RETTOK(DNS_R_BADDOTTEDQUAD); 88 } 89 isc_buffer_availableregion(target, ®ion); 90 if (region.length < 4) { 91 return ISC_R_NOSPACE; 92 } 93 memmove(region.base, &addr, 4); 94 isc_buffer_add(target, 4); 95 break; 96 97 case 2: 98 if (inet_pton(AF_INET6, DNS_AS_STR(token), addr6) != 1) { 99 RETTOK(DNS_R_BADAAAA); 100 } 101 isc_buffer_availableregion(target, ®ion); 102 if (region.length < 16) { 103 return ISC_R_NOSPACE; 104 } 105 memmove(region.base, addr6, 16); 106 isc_buffer_add(target, 16); 107 break; 108 109 case 3: 110 dns_name_init(&name, NULL); 111 buffer_fromregion(&buffer, &token.value.as_region); 112 if (origin == NULL) { 113 origin = dns_rootname; 114 } 115 RETTOK(dns_name_fromtext(&name, &buffer, origin, options, 116 target)); 117 break; 118 } 119 120 /* 121 * Public key. 122 */ 123 return isc_base64_tobuffer(lexer, target, -2); 124 } 125 126 static isc_result_t 127 totext_ipseckey(ARGS_TOTEXT) { 128 isc_region_t region; 129 dns_name_t name; 130 char buf[sizeof("255 ")]; 131 unsigned short num; 132 unsigned short gateway; 133 134 REQUIRE(rdata->type == dns_rdatatype_ipseckey); 135 REQUIRE(rdata->length >= 3); 136 137 dns_name_init(&name, NULL); 138 139 if (rdata->data[1] > 3U) { 140 return ISC_R_NOTIMPLEMENTED; 141 } 142 143 if ((tctx->flags & DNS_STYLEFLAG_MULTILINE) != 0) { 144 RETERR(str_totext("( ", target)); 145 } 146 147 /* 148 * Precedence. 149 */ 150 dns_rdata_toregion(rdata, ®ion); 151 num = uint8_fromregion(®ion); 152 isc_region_consume(®ion, 1); 153 snprintf(buf, sizeof(buf), "%u ", num); 154 RETERR(str_totext(buf, target)); 155 156 /* 157 * Gateway type. 158 */ 159 gateway = uint8_fromregion(®ion); 160 isc_region_consume(®ion, 1); 161 snprintf(buf, sizeof(buf), "%u ", gateway); 162 RETERR(str_totext(buf, target)); 163 164 /* 165 * Algorithm. 166 */ 167 num = uint8_fromregion(®ion); 168 isc_region_consume(®ion, 1); 169 snprintf(buf, sizeof(buf), "%u ", num); 170 RETERR(str_totext(buf, target)); 171 172 /* 173 * Gateway. 174 */ 175 switch (gateway) { 176 case 0: 177 RETERR(str_totext(".", target)); 178 break; 179 180 case 1: 181 RETERR(inet_totext(AF_INET, tctx->flags, ®ion, target)); 182 isc_region_consume(®ion, 4); 183 break; 184 185 case 2: 186 RETERR(inet_totext(AF_INET6, tctx->flags, ®ion, target)); 187 isc_region_consume(®ion, 16); 188 break; 189 190 case 3: 191 dns_name_fromregion(&name, ®ion); 192 RETERR(dns_name_totext(&name, 0, target)); 193 isc_region_consume(®ion, name_length(&name)); 194 break; 195 } 196 197 /* 198 * Key. 199 */ 200 if (region.length > 0U) { 201 RETERR(str_totext(tctx->linebreak, target)); 202 if (tctx->width == 0) { /* No splitting */ 203 RETERR(isc_base64_totext(®ion, 60, "", target)); 204 } else { 205 RETERR(isc_base64_totext(®ion, tctx->width - 2, 206 tctx->linebreak, target)); 207 } 208 } 209 210 if ((tctx->flags & DNS_STYLEFLAG_MULTILINE) != 0) { 211 RETERR(str_totext(" )", target)); 212 } 213 return ISC_R_SUCCESS; 214 } 215 216 static isc_result_t 217 fromwire_ipseckey(ARGS_FROMWIRE) { 218 dns_name_t name; 219 isc_region_t region; 220 221 REQUIRE(type == dns_rdatatype_ipseckey); 222 223 UNUSED(type); 224 UNUSED(rdclass); 225 226 dctx = dns_decompress_setpermitted(dctx, false); 227 228 dns_name_init(&name, NULL); 229 230 isc_buffer_activeregion(source, ®ion); 231 if (region.length < 3) { 232 return ISC_R_UNEXPECTEDEND; 233 } 234 235 switch (region.base[1]) { 236 case 0: 237 if (region.length < 4) { 238 return ISC_R_UNEXPECTEDEND; 239 } 240 isc_buffer_forward(source, region.length); 241 return mem_tobuffer(target, region.base, region.length); 242 243 case 1: 244 if (region.length < 8) { 245 return ISC_R_UNEXPECTEDEND; 246 } 247 isc_buffer_forward(source, region.length); 248 return mem_tobuffer(target, region.base, region.length); 249 250 case 2: 251 if (region.length < 20) { 252 return ISC_R_UNEXPECTEDEND; 253 } 254 isc_buffer_forward(source, region.length); 255 return mem_tobuffer(target, region.base, region.length); 256 257 case 3: 258 RETERR(mem_tobuffer(target, region.base, 3)); 259 isc_buffer_forward(source, 3); 260 RETERR(dns_name_fromwire(&name, source, dctx, target)); 261 isc_buffer_activeregion(source, ®ion); 262 isc_buffer_forward(source, region.length); 263 if (region.length < 1) { 264 return ISC_R_UNEXPECTEDEND; 265 } 266 return mem_tobuffer(target, region.base, region.length); 267 268 default: 269 return ISC_R_NOTIMPLEMENTED; 270 } 271 } 272 273 static isc_result_t 274 towire_ipseckey(ARGS_TOWIRE) { 275 isc_region_t region; 276 277 REQUIRE(rdata->type == dns_rdatatype_ipseckey); 278 REQUIRE(rdata->length != 0); 279 280 UNUSED(cctx); 281 282 dns_rdata_toregion(rdata, ®ion); 283 return mem_tobuffer(target, region.base, region.length); 284 } 285 286 static int 287 compare_ipseckey(ARGS_COMPARE) { 288 isc_region_t region1; 289 isc_region_t region2; 290 291 REQUIRE(rdata1->type == rdata2->type); 292 REQUIRE(rdata1->rdclass == rdata2->rdclass); 293 REQUIRE(rdata1->type == dns_rdatatype_ipseckey); 294 REQUIRE(rdata1->length >= 3); 295 REQUIRE(rdata2->length >= 3); 296 297 dns_rdata_toregion(rdata1, ®ion1); 298 dns_rdata_toregion(rdata2, ®ion2); 299 300 return isc_region_compare(®ion1, ®ion2); 301 } 302 303 static isc_result_t 304 fromstruct_ipseckey(ARGS_FROMSTRUCT) { 305 dns_rdata_ipseckey_t *ipseckey = source; 306 isc_region_t region; 307 uint32_t n; 308 309 REQUIRE(type == dns_rdatatype_ipseckey); 310 REQUIRE(ipseckey != NULL); 311 REQUIRE(ipseckey->common.rdtype == type); 312 REQUIRE(ipseckey->common.rdclass == rdclass); 313 314 UNUSED(type); 315 UNUSED(rdclass); 316 317 if (ipseckey->gateway_type > 3U) { 318 return ISC_R_NOTIMPLEMENTED; 319 } 320 321 RETERR(uint8_tobuffer(ipseckey->precedence, target)); 322 RETERR(uint8_tobuffer(ipseckey->gateway_type, target)); 323 RETERR(uint8_tobuffer(ipseckey->algorithm, target)); 324 325 switch (ipseckey->gateway_type) { 326 case 0: 327 break; 328 329 case 1: 330 n = ntohl(ipseckey->in_addr.s_addr); 331 RETERR(uint32_tobuffer(n, target)); 332 break; 333 334 case 2: 335 RETERR(mem_tobuffer(target, ipseckey->in6_addr.s6_addr, 16)); 336 break; 337 338 case 3: 339 dns_name_toregion(&ipseckey->gateway, ®ion); 340 RETERR(isc_buffer_copyregion(target, ®ion)); 341 break; 342 } 343 344 return mem_tobuffer(target, ipseckey->key, ipseckey->keylength); 345 } 346 347 static isc_result_t 348 tostruct_ipseckey(ARGS_TOSTRUCT) { 349 isc_region_t region; 350 dns_rdata_ipseckey_t *ipseckey = target; 351 dns_name_t name; 352 uint32_t n; 353 354 REQUIRE(rdata->type == dns_rdatatype_ipseckey); 355 REQUIRE(ipseckey != NULL); 356 REQUIRE(rdata->length >= 3); 357 358 ipseckey->common.rdclass = rdata->rdclass; 359 ipseckey->common.rdtype = rdata->type; 360 ISC_LINK_INIT(&ipseckey->common, link); 361 362 dns_name_init(&name, NULL); 363 dns_rdata_toregion(rdata, ®ion); 364 365 ipseckey->precedence = uint8_fromregion(®ion); 366 isc_region_consume(®ion, 1); 367 368 ipseckey->gateway_type = uint8_fromregion(®ion); 369 isc_region_consume(®ion, 1); 370 371 ipseckey->algorithm = uint8_fromregion(®ion); 372 isc_region_consume(®ion, 1); 373 374 switch (ipseckey->gateway_type) { 375 case 0: 376 break; 377 378 case 1: 379 n = uint32_fromregion(®ion); 380 ipseckey->in_addr.s_addr = htonl(n); 381 isc_region_consume(®ion, 4); 382 break; 383 384 case 2: 385 INSIST(region.length >= 16U); 386 memmove(ipseckey->in6_addr.s6_addr, region.base, 16); 387 isc_region_consume(®ion, 16); 388 break; 389 390 case 3: 391 dns_name_init(&ipseckey->gateway, NULL); 392 dns_name_fromregion(&name, ®ion); 393 name_duporclone(&name, mctx, &ipseckey->gateway); 394 isc_region_consume(®ion, name_length(&name)); 395 break; 396 } 397 398 ipseckey->keylength = region.length; 399 if (ipseckey->keylength != 0U) { 400 ipseckey->key = mem_maybedup(mctx, region.base, 401 ipseckey->keylength); 402 } else { 403 ipseckey->key = NULL; 404 } 405 406 ipseckey->mctx = mctx; 407 return ISC_R_SUCCESS; 408 } 409 410 static void 411 freestruct_ipseckey(ARGS_FREESTRUCT) { 412 dns_rdata_ipseckey_t *ipseckey = source; 413 414 REQUIRE(ipseckey != NULL); 415 REQUIRE(ipseckey->common.rdtype == dns_rdatatype_ipseckey); 416 417 if (ipseckey->mctx == NULL) { 418 return; 419 } 420 421 if (ipseckey->gateway_type == 3) { 422 dns_name_free(&ipseckey->gateway, ipseckey->mctx); 423 } 424 425 if (ipseckey->key != NULL) { 426 isc_mem_free(ipseckey->mctx, ipseckey->key); 427 } 428 429 ipseckey->mctx = NULL; 430 } 431 432 static isc_result_t 433 additionaldata_ipseckey(ARGS_ADDLDATA) { 434 REQUIRE(rdata->type == dns_rdatatype_ipseckey); 435 436 UNUSED(rdata); 437 UNUSED(owner); 438 UNUSED(add); 439 UNUSED(arg); 440 441 return ISC_R_SUCCESS; 442 } 443 444 static isc_result_t 445 digest_ipseckey(ARGS_DIGEST) { 446 isc_region_t region; 447 448 REQUIRE(rdata->type == dns_rdatatype_ipseckey); 449 450 dns_rdata_toregion(rdata, ®ion); 451 return (digest)(arg, ®ion); 452 } 453 454 static bool 455 checkowner_ipseckey(ARGS_CHECKOWNER) { 456 REQUIRE(type == dns_rdatatype_ipseckey); 457 458 UNUSED(name); 459 UNUSED(type); 460 UNUSED(rdclass); 461 UNUSED(wildcard); 462 463 return true; 464 } 465 466 static bool 467 checknames_ipseckey(ARGS_CHECKNAMES) { 468 REQUIRE(rdata->type == dns_rdatatype_ipseckey); 469 470 UNUSED(rdata); 471 UNUSED(owner); 472 UNUSED(bad); 473 474 return true; 475 } 476 477 static int 478 casecompare_ipseckey(ARGS_COMPARE) { 479 isc_region_t region1; 480 isc_region_t region2; 481 dns_name_t name1; 482 dns_name_t name2; 483 int order; 484 485 REQUIRE(rdata1->type == rdata2->type); 486 REQUIRE(rdata1->rdclass == rdata2->rdclass); 487 REQUIRE(rdata1->type == dns_rdatatype_ipseckey); 488 REQUIRE(rdata1->length >= 3); 489 REQUIRE(rdata2->length >= 3); 490 491 dns_rdata_toregion(rdata1, ®ion1); 492 dns_rdata_toregion(rdata2, ®ion2); 493 494 if (memcmp(region1.base, region2.base, 3) != 0 || region1.base[1] != 3) 495 { 496 return isc_region_compare(®ion1, ®ion2); 497 } 498 499 dns_name_init(&name1, NULL); 500 dns_name_init(&name2, NULL); 501 502 isc_region_consume(®ion1, 3); 503 isc_region_consume(®ion2, 3); 504 505 dns_name_fromregion(&name1, ®ion1); 506 dns_name_fromregion(&name2, ®ion2); 507 508 order = dns_name_rdatacompare(&name1, &name2); 509 if (order != 0) { 510 return order; 511 } 512 513 isc_region_consume(®ion1, name_length(&name1)); 514 isc_region_consume(®ion2, name_length(&name2)); 515 516 return isc_region_compare(®ion1, ®ion2); 517 } 518 519 #endif /* RDATA_GENERIC_IPSECKEY_45_C */ 520