1 /* $NetBSD: soa_6.c,v 1.1 2024/02/18 20:57:44 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_SOA_6_C 17 #define RDATA_GENERIC_SOA_6_C 18 19 #define RRTYPE_SOA_ATTRIBUTES (DNS_RDATATYPEATTR_SINGLETON) 20 21 static isc_result_t 22 fromtext_soa(ARGS_FROMTEXT) { 23 isc_token_t token; 24 dns_name_t name; 25 isc_buffer_t buffer; 26 int i; 27 uint32_t n; 28 bool ok; 29 30 REQUIRE(type == dns_rdatatype_soa); 31 32 UNUSED(type); 33 UNUSED(rdclass); 34 UNUSED(callbacks); 35 36 if (origin == NULL) { 37 origin = dns_rootname; 38 } 39 40 for (i = 0; i < 2; i++) { 41 RETERR(isc_lex_getmastertoken(lexer, &token, 42 isc_tokentype_string, false)); 43 44 dns_name_init(&name, NULL); 45 buffer_fromregion(&buffer, &token.value.as_region); 46 RETTOK(dns_name_fromtext(&name, &buffer, origin, options, 47 target)); 48 ok = true; 49 if ((options & DNS_RDATA_CHECKNAMES) != 0) { 50 switch (i) { 51 case 0: 52 ok = dns_name_ishostname(&name, false); 53 break; 54 case 1: 55 ok = dns_name_ismailbox(&name); 56 break; 57 } 58 } 59 if (!ok && (options & DNS_RDATA_CHECKNAMESFAIL) != 0) { 60 RETTOK(DNS_R_BADNAME); 61 } 62 if (!ok && callbacks != NULL) { 63 warn_badname(&name, lexer, callbacks); 64 } 65 } 66 67 RETERR(isc_lex_getmastertoken(lexer, &token, isc_tokentype_number, 68 false)); 69 RETERR(uint32_tobuffer(token.value.as_ulong, target)); 70 71 for (i = 0; i < 4; i++) { 72 RETERR(isc_lex_getmastertoken(lexer, &token, 73 isc_tokentype_string, false)); 74 RETTOK(dns_counter_fromtext(&token.value.as_textregion, &n)); 75 RETERR(uint32_tobuffer(n, target)); 76 } 77 78 return (ISC_R_SUCCESS); 79 } 80 81 static const char *soa_fieldnames[5] = { "serial", "refresh", "retry", "expire", 82 "minimum" }; 83 84 static isc_result_t 85 totext_soa(ARGS_TOTEXT) { 86 isc_region_t dregion; 87 dns_name_t mname; 88 dns_name_t rname; 89 dns_name_t prefix; 90 bool sub; 91 int i; 92 bool multiline; 93 bool comm; 94 95 REQUIRE(rdata->type == dns_rdatatype_soa); 96 REQUIRE(rdata->length != 0); 97 98 multiline = ((tctx->flags & DNS_STYLEFLAG_MULTILINE) != 0); 99 if (multiline) { 100 comm = ((tctx->flags & DNS_STYLEFLAG_RRCOMMENT) != 0); 101 } else { 102 comm = false; 103 } 104 105 dns_name_init(&mname, NULL); 106 dns_name_init(&rname, NULL); 107 dns_name_init(&prefix, NULL); 108 109 dns_rdata_toregion(rdata, &dregion); 110 111 dns_name_fromregion(&mname, &dregion); 112 isc_region_consume(&dregion, name_length(&mname)); 113 114 dns_name_fromregion(&rname, &dregion); 115 isc_region_consume(&dregion, name_length(&rname)); 116 117 sub = name_prefix(&mname, tctx->origin, &prefix); 118 RETERR(dns_name_totext(&prefix, sub, target)); 119 120 RETERR(str_totext(" ", target)); 121 122 sub = name_prefix(&rname, tctx->origin, &prefix); 123 RETERR(dns_name_totext(&prefix, sub, target)); 124 125 if (multiline) { 126 RETERR(str_totext(" (", target)); 127 } 128 RETERR(str_totext(tctx->linebreak, target)); 129 130 for (i = 0; i < 5; i++) { 131 char buf[sizeof("0123456789 ; ")]; 132 unsigned long num; 133 num = uint32_fromregion(&dregion); 134 isc_region_consume(&dregion, 4); 135 snprintf(buf, sizeof(buf), comm ? "%-10lu ; " : "%lu", num); 136 RETERR(str_totext(buf, target)); 137 if (comm) { 138 RETERR(str_totext(soa_fieldnames[i], target)); 139 /* Print times in week/day/hour/minute/second form */ 140 if (i >= 1) { 141 RETERR(str_totext(" (", target)); 142 RETERR(dns_ttl_totext(num, true, true, target)); 143 RETERR(str_totext(")", target)); 144 } 145 RETERR(str_totext(tctx->linebreak, target)); 146 } else if (i < 4) { 147 RETERR(str_totext(tctx->linebreak, target)); 148 } 149 } 150 151 if (multiline) { 152 RETERR(str_totext(")", target)); 153 } 154 155 return (ISC_R_SUCCESS); 156 } 157 158 static isc_result_t 159 fromwire_soa(ARGS_FROMWIRE) { 160 dns_name_t mname; 161 dns_name_t rname; 162 isc_region_t sregion; 163 isc_region_t tregion; 164 165 REQUIRE(type == dns_rdatatype_soa); 166 167 UNUSED(type); 168 UNUSED(rdclass); 169 170 dns_decompress_setmethods(dctx, DNS_COMPRESS_GLOBAL14); 171 172 dns_name_init(&mname, NULL); 173 dns_name_init(&rname, NULL); 174 175 RETERR(dns_name_fromwire(&mname, source, dctx, options, target)); 176 RETERR(dns_name_fromwire(&rname, source, dctx, options, target)); 177 178 isc_buffer_activeregion(source, &sregion); 179 isc_buffer_availableregion(target, &tregion); 180 181 if (sregion.length < 20) { 182 return (ISC_R_UNEXPECTEDEND); 183 } 184 if (tregion.length < 20) { 185 return (ISC_R_NOSPACE); 186 } 187 188 memmove(tregion.base, sregion.base, 20); 189 isc_buffer_forward(source, 20); 190 isc_buffer_add(target, 20); 191 192 return (ISC_R_SUCCESS); 193 } 194 195 static isc_result_t 196 towire_soa(ARGS_TOWIRE) { 197 isc_region_t sregion; 198 isc_region_t tregion; 199 dns_name_t mname; 200 dns_name_t rname; 201 dns_offsets_t moffsets; 202 dns_offsets_t roffsets; 203 204 REQUIRE(rdata->type == dns_rdatatype_soa); 205 REQUIRE(rdata->length != 0); 206 207 dns_compress_setmethods(cctx, DNS_COMPRESS_GLOBAL14); 208 209 dns_name_init(&mname, moffsets); 210 dns_name_init(&rname, roffsets); 211 212 dns_rdata_toregion(rdata, &sregion); 213 214 dns_name_fromregion(&mname, &sregion); 215 isc_region_consume(&sregion, name_length(&mname)); 216 RETERR(dns_name_towire(&mname, cctx, target)); 217 218 dns_name_fromregion(&rname, &sregion); 219 isc_region_consume(&sregion, name_length(&rname)); 220 RETERR(dns_name_towire(&rname, cctx, target)); 221 222 isc_buffer_availableregion(target, &tregion); 223 if (tregion.length < 20) { 224 return (ISC_R_NOSPACE); 225 } 226 227 memmove(tregion.base, sregion.base, 20); 228 isc_buffer_add(target, 20); 229 return (ISC_R_SUCCESS); 230 } 231 232 static int 233 compare_soa(ARGS_COMPARE) { 234 isc_region_t region1; 235 isc_region_t region2; 236 dns_name_t name1; 237 dns_name_t name2; 238 int order; 239 240 REQUIRE(rdata1->type == rdata2->type); 241 REQUIRE(rdata1->rdclass == rdata2->rdclass); 242 REQUIRE(rdata1->type == dns_rdatatype_soa); 243 REQUIRE(rdata1->length != 0); 244 REQUIRE(rdata2->length != 0); 245 246 dns_name_init(&name1, NULL); 247 dns_name_init(&name2, NULL); 248 249 dns_rdata_toregion(rdata1, ®ion1); 250 dns_rdata_toregion(rdata2, ®ion2); 251 252 dns_name_fromregion(&name1, ®ion1); 253 dns_name_fromregion(&name2, ®ion2); 254 255 order = dns_name_rdatacompare(&name1, &name2); 256 if (order != 0) { 257 return (order); 258 } 259 260 isc_region_consume(®ion1, name_length(&name1)); 261 isc_region_consume(®ion2, name_length(&name2)); 262 263 dns_name_init(&name1, NULL); 264 dns_name_init(&name2, NULL); 265 266 dns_name_fromregion(&name1, ®ion1); 267 dns_name_fromregion(&name2, ®ion2); 268 269 order = dns_name_rdatacompare(&name1, &name2); 270 if (order != 0) { 271 return (order); 272 } 273 274 isc_region_consume(®ion1, name_length(&name1)); 275 isc_region_consume(®ion2, name_length(&name2)); 276 277 return (isc_region_compare(®ion1, ®ion2)); 278 } 279 280 static isc_result_t 281 fromstruct_soa(ARGS_FROMSTRUCT) { 282 dns_rdata_soa_t *soa = source; 283 isc_region_t region; 284 285 REQUIRE(type == dns_rdatatype_soa); 286 REQUIRE(soa != NULL); 287 REQUIRE(soa->common.rdtype == type); 288 REQUIRE(soa->common.rdclass == rdclass); 289 290 UNUSED(type); 291 UNUSED(rdclass); 292 293 dns_name_toregion(&soa->origin, ®ion); 294 RETERR(isc_buffer_copyregion(target, ®ion)); 295 dns_name_toregion(&soa->contact, ®ion); 296 RETERR(isc_buffer_copyregion(target, ®ion)); 297 RETERR(uint32_tobuffer(soa->serial, target)); 298 RETERR(uint32_tobuffer(soa->refresh, target)); 299 RETERR(uint32_tobuffer(soa->retry, target)); 300 RETERR(uint32_tobuffer(soa->expire, target)); 301 return (uint32_tobuffer(soa->minimum, target)); 302 } 303 304 static isc_result_t 305 tostruct_soa(ARGS_TOSTRUCT) { 306 isc_region_t region; 307 dns_rdata_soa_t *soa = target; 308 dns_name_t name; 309 isc_result_t result; 310 311 REQUIRE(rdata->type == dns_rdatatype_soa); 312 REQUIRE(soa != NULL); 313 REQUIRE(rdata->length != 0); 314 315 soa->common.rdclass = rdata->rdclass; 316 soa->common.rdtype = rdata->type; 317 ISC_LINK_INIT(&soa->common, link); 318 319 dns_rdata_toregion(rdata, ®ion); 320 321 dns_name_init(&name, NULL); 322 dns_name_fromregion(&name, ®ion); 323 isc_region_consume(®ion, name_length(&name)); 324 dns_name_init(&soa->origin, NULL); 325 RETERR(name_duporclone(&name, mctx, &soa->origin)); 326 327 dns_name_fromregion(&name, ®ion); 328 isc_region_consume(®ion, name_length(&name)); 329 dns_name_init(&soa->contact, NULL); 330 result = name_duporclone(&name, mctx, &soa->contact); 331 if (result != ISC_R_SUCCESS) { 332 goto cleanup; 333 } 334 335 soa->serial = uint32_fromregion(®ion); 336 isc_region_consume(®ion, 4); 337 338 soa->refresh = uint32_fromregion(®ion); 339 isc_region_consume(®ion, 4); 340 341 soa->retry = uint32_fromregion(®ion); 342 isc_region_consume(®ion, 4); 343 344 soa->expire = uint32_fromregion(®ion); 345 isc_region_consume(®ion, 4); 346 347 soa->minimum = uint32_fromregion(®ion); 348 349 soa->mctx = mctx; 350 return (ISC_R_SUCCESS); 351 352 cleanup: 353 if (mctx != NULL) { 354 dns_name_free(&soa->origin, mctx); 355 } 356 return (ISC_R_NOMEMORY); 357 } 358 359 static void 360 freestruct_soa(ARGS_FREESTRUCT) { 361 dns_rdata_soa_t *soa = source; 362 363 REQUIRE(soa != NULL); 364 REQUIRE(soa->common.rdtype == dns_rdatatype_soa); 365 366 if (soa->mctx == NULL) { 367 return; 368 } 369 370 dns_name_free(&soa->origin, soa->mctx); 371 dns_name_free(&soa->contact, soa->mctx); 372 soa->mctx = NULL; 373 } 374 375 static isc_result_t 376 additionaldata_soa(ARGS_ADDLDATA) { 377 UNUSED(rdata); 378 UNUSED(add); 379 UNUSED(arg); 380 381 REQUIRE(rdata->type == dns_rdatatype_soa); 382 383 return (ISC_R_SUCCESS); 384 } 385 386 static isc_result_t 387 digest_soa(ARGS_DIGEST) { 388 isc_region_t r; 389 dns_name_t name; 390 391 REQUIRE(rdata->type == dns_rdatatype_soa); 392 393 dns_rdata_toregion(rdata, &r); 394 395 dns_name_init(&name, NULL); 396 dns_name_fromregion(&name, &r); 397 RETERR(dns_name_digest(&name, digest, arg)); 398 isc_region_consume(&r, name_length(&name)); 399 400 dns_name_init(&name, NULL); 401 dns_name_fromregion(&name, &r); 402 RETERR(dns_name_digest(&name, digest, arg)); 403 isc_region_consume(&r, name_length(&name)); 404 405 return ((digest)(arg, &r)); 406 } 407 408 static bool 409 checkowner_soa(ARGS_CHECKOWNER) { 410 REQUIRE(type == dns_rdatatype_soa); 411 412 UNUSED(name); 413 UNUSED(type); 414 UNUSED(rdclass); 415 UNUSED(wildcard); 416 417 return (true); 418 } 419 420 static bool 421 checknames_soa(ARGS_CHECKNAMES) { 422 isc_region_t region; 423 dns_name_t name; 424 425 REQUIRE(rdata->type == dns_rdatatype_soa); 426 427 UNUSED(owner); 428 429 dns_rdata_toregion(rdata, ®ion); 430 dns_name_init(&name, NULL); 431 dns_name_fromregion(&name, ®ion); 432 if (!dns_name_ishostname(&name, false)) { 433 if (bad != NULL) { 434 dns_name_clone(&name, bad); 435 } 436 return (false); 437 } 438 isc_region_consume(®ion, name_length(&name)); 439 dns_name_fromregion(&name, ®ion); 440 if (!dns_name_ismailbox(&name)) { 441 if (bad != NULL) { 442 dns_name_clone(&name, bad); 443 } 444 return (false); 445 } 446 return (true); 447 } 448 449 static int 450 casecompare_soa(ARGS_COMPARE) { 451 return (compare_soa(rdata1, rdata2)); 452 } 453 454 #endif /* RDATA_GENERIC_SOA_6_C */ 455