00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022 #include <config.h>
00023
00024 #include <stdlib.h>
00025
00026 #include <isc/buffer.h>
00027 #include <isc/file.h>
00028 #include <isc/mem.h>
00029 #include <isc/string.h>
00030 #include <isc/util.h>
00031
00032 #include <dns/db.h>
00033 #include <dns/diff.h>
00034 #include <dns/log.h>
00035 #include <dns/rdataclass.h>
00036 #include <dns/rdatalist.h>
00037 #include <dns/rdataset.h>
00038 #include <dns/rdatastruct.h>
00039 #include <dns/rdatatype.h>
00040 #include <dns/result.h>
00041
00042 #define CHECK(op) \
00043 do { result = (op); \
00044 if (result != ISC_R_SUCCESS) goto failure; \
00045 } while (0)
00046
00047 #define DIFF_COMMON_LOGARGS \
00048 dns_lctx, DNS_LOGCATEGORY_GENERAL, DNS_LOGMODULE_DIFF
00049
00050 static dns_rdatatype_t
00051 rdata_covers(dns_rdata_t *rdata) {
00052 return (rdata->type == dns_rdatatype_rrsig ?
00053 dns_rdata_covers(rdata) : 0);
00054 }
00055
00056 isc_result_t
00057 dns_difftuple_create(isc_mem_t *mctx,
00058 dns_diffop_t op, dns_name_t *name, dns_ttl_t ttl,
00059 dns_rdata_t *rdata, dns_difftuple_t **tp)
00060 {
00061 dns_difftuple_t *t;
00062 unsigned int size;
00063 unsigned char *datap;
00064
00065 REQUIRE(tp != NULL && *tp == NULL);
00066
00067
00068
00069
00070
00071
00072 size = sizeof(*t) + name->length + rdata->length;
00073 t = isc_mem_allocate(mctx, size);
00074 if (t == NULL)
00075 return (ISC_R_NOMEMORY);
00076 t->mctx = NULL;
00077 isc_mem_attach(mctx, &t->mctx);
00078 t->op = op;
00079
00080 datap = (unsigned char *)(t + 1);
00081
00082 memmove(datap, name->ndata, name->length);
00083 dns_name_init(&t->name, NULL);
00084 dns_name_clone(name, &t->name);
00085 t->name.ndata = datap;
00086 datap += name->length;
00087
00088 t->ttl = ttl;
00089
00090 memmove(datap, rdata->data, rdata->length);
00091 dns_rdata_init(&t->rdata);
00092 dns_rdata_clone(rdata, &t->rdata);
00093 t->rdata.data = datap;
00094 datap += rdata->length;
00095
00096 ISC_LINK_INIT(&t->rdata, link);
00097 ISC_LINK_INIT(t, link);
00098 t->magic = DNS_DIFFTUPLE_MAGIC;
00099
00100 INSIST(datap == (unsigned char *)t + size);
00101
00102 *tp = t;
00103 return (ISC_R_SUCCESS);
00104 }
00105
00106 void
00107 dns_difftuple_free(dns_difftuple_t **tp) {
00108 dns_difftuple_t *t = *tp;
00109 isc_mem_t *mctx;
00110
00111 REQUIRE(DNS_DIFFTUPLE_VALID(t));
00112
00113 dns_name_invalidate(&t->name);
00114 t->magic = 0;
00115 mctx = t->mctx;
00116 isc_mem_free(mctx, t);
00117 isc_mem_detach(&mctx);
00118 *tp = NULL;
00119 }
00120
00121 isc_result_t
00122 dns_difftuple_copy(dns_difftuple_t *orig, dns_difftuple_t **copyp) {
00123 return (dns_difftuple_create(orig->mctx, orig->op, &orig->name,
00124 orig->ttl, &orig->rdata, copyp));
00125 }
00126
00127 void
00128 dns_diff_init(isc_mem_t *mctx, dns_diff_t *diff) {
00129 diff->mctx = mctx;
00130 ISC_LIST_INIT(diff->tuples);
00131 diff->magic = DNS_DIFF_MAGIC;
00132 }
00133
00134 void
00135 dns_diff_clear(dns_diff_t *diff) {
00136 dns_difftuple_t *t;
00137 REQUIRE(DNS_DIFF_VALID(diff));
00138 while ((t = ISC_LIST_HEAD(diff->tuples)) != NULL) {
00139 ISC_LIST_UNLINK(diff->tuples, t, link);
00140 dns_difftuple_free(&t);
00141 }
00142 ENSURE(ISC_LIST_EMPTY(diff->tuples));
00143 }
00144
00145 void
00146 dns_diff_append(dns_diff_t *diff, dns_difftuple_t **tuplep)
00147 {
00148 ISC_LIST_APPEND(diff->tuples, *tuplep, link);
00149 *tuplep = NULL;
00150 }
00151
00152
00153
00154 void
00155 dns_diff_appendminimal(dns_diff_t *diff, dns_difftuple_t **tuplep)
00156 {
00157 dns_difftuple_t *ot, *next_ot;
00158
00159 REQUIRE(DNS_DIFF_VALID(diff));
00160 REQUIRE(DNS_DIFFTUPLE_VALID(*tuplep));
00161
00162
00163
00164
00165
00166
00167
00168
00169
00170
00171
00172
00173
00174 for (ot = ISC_LIST_HEAD(diff->tuples); ot != NULL;
00175 ot = next_ot)
00176 {
00177 next_ot = ISC_LIST_NEXT(ot, link);
00178 if (dns_name_caseequal(&ot->name, &(*tuplep)->name) &&
00179 dns_rdata_compare(&ot->rdata, &(*tuplep)->rdata) == 0 &&
00180 ot->ttl == (*tuplep)->ttl)
00181 {
00182 ISC_LIST_UNLINK(diff->tuples, ot, link);
00183 if ((*tuplep)->op == ot->op) {
00184 UNEXPECTED_ERROR(__FILE__, __LINE__,
00185 "unexpected non-minimal diff");
00186 } else {
00187 dns_difftuple_free(tuplep);
00188 }
00189 dns_difftuple_free(&ot);
00190 break;
00191 }
00192 }
00193
00194 if (*tuplep != NULL) {
00195 ISC_LIST_APPEND(diff->tuples, *tuplep, link);
00196 *tuplep = NULL;
00197 }
00198
00199 ENSURE(*tuplep == NULL);
00200 }
00201
00202 static isc_stdtime_t
00203 setresign(dns_rdataset_t *modified) {
00204 dns_rdata_t rdata = DNS_RDATA_INIT;
00205 dns_rdata_rrsig_t sig;
00206 isc_stdtime_t when;
00207 isc_result_t result;
00208
00209 result = dns_rdataset_first(modified);
00210 INSIST(result == ISC_R_SUCCESS);
00211 dns_rdataset_current(modified, &rdata);
00212 (void)dns_rdata_tostruct(&rdata, &sig, NULL);
00213 if ((rdata.flags & DNS_RDATA_OFFLINE) != 0)
00214 when = 0;
00215 else
00216 when = sig.timeexpire;
00217 dns_rdata_reset(&rdata);
00218
00219 result = dns_rdataset_next(modified);
00220 while (result == ISC_R_SUCCESS) {
00221 dns_rdataset_current(modified, &rdata);
00222 (void)dns_rdata_tostruct(&rdata, &sig, NULL);
00223 if ((rdata.flags & DNS_RDATA_OFFLINE) != 0) {
00224 goto next_rr;
00225 }
00226 if (when == 0 || sig.timeexpire < when)
00227 when = sig.timeexpire;
00228 next_rr:
00229 dns_rdata_reset(&rdata);
00230 result = dns_rdataset_next(modified);
00231 }
00232 INSIST(result == ISC_R_NOMORE);
00233 return (when);
00234 }
00235
00236 static void
00237 getownercase(dns_rdataset_t *rdataset, dns_name_t *name) {
00238 if (dns_rdataset_isassociated(rdataset))
00239 dns_rdataset_getownercase(rdataset, name);
00240 }
00241
00242 static void
00243 setownercase(dns_rdataset_t *rdataset, dns_name_t *name) {
00244 if (dns_rdataset_isassociated(rdataset))
00245 dns_rdataset_setownercase(rdataset, name);
00246 }
00247
00248 static isc_result_t
00249 diff_apply(dns_diff_t *diff, dns_db_t *db, dns_dbversion_t *ver,
00250 isc_boolean_t warn)
00251 {
00252 dns_difftuple_t *t;
00253 dns_dbnode_t *node = NULL;
00254 isc_result_t result;
00255 char namebuf[DNS_NAME_FORMATSIZE];
00256 char typebuf[DNS_RDATATYPE_FORMATSIZE];
00257 char classbuf[DNS_RDATACLASS_FORMATSIZE];
00258
00259 REQUIRE(DNS_DIFF_VALID(diff));
00260 REQUIRE(DNS_DB_VALID(db));
00261
00262 t = ISC_LIST_HEAD(diff->tuples);
00263 while (t != NULL) {
00264 dns_name_t *name;
00265
00266 INSIST(node == NULL);
00267 name = &t->name;
00268
00269
00270
00271
00272
00273
00274
00275
00276
00277 while (t != NULL && dns_name_equal(&t->name, name)) {
00278 dns_rdatatype_t type, covers;
00279 dns_diffop_t op;
00280 dns_rdatalist_t rdl;
00281 dns_rdataset_t rds;
00282 dns_rdataset_t ardataset;
00283 unsigned int options;
00284
00285 op = t->op;
00286 type = t->rdata.type;
00287 covers = rdata_covers(&t->rdata);
00288
00289
00290
00291
00292
00293
00294
00295
00296
00297
00298
00299
00300
00301
00302
00303
00304 dns_rdatalist_init(&rdl);
00305 rdl.type = type;
00306 rdl.covers = covers;
00307 rdl.rdclass = t->rdata.rdclass;
00308 rdl.ttl = t->ttl;
00309
00310 node = NULL;
00311 if (type != dns_rdatatype_nsec3 &&
00312 covers != dns_rdatatype_nsec3)
00313 CHECK(dns_db_findnode(db, name, ISC_TRUE,
00314 &node));
00315 else
00316 CHECK(dns_db_findnsec3node(db, name, ISC_TRUE,
00317 &node));
00318
00319 while (t != NULL &&
00320 dns_name_equal(&t->name, name) &&
00321 t->op == op &&
00322 t->rdata.type == type &&
00323 rdata_covers(&t->rdata) == covers)
00324 {
00325
00326
00327
00328
00329 name = &t->name;
00330 if (t->ttl != rdl.ttl && warn) {
00331 dns_name_format(name, namebuf,
00332 sizeof(namebuf));
00333 dns_rdatatype_format(t->rdata.type,
00334 typebuf,
00335 sizeof(typebuf));
00336 dns_rdataclass_format(t->rdata.rdclass,
00337 classbuf,
00338 sizeof(classbuf));
00339 isc_log_write(DIFF_COMMON_LOGARGS,
00340 ISC_LOG_WARNING,
00341 "'%s/%s/%s': TTL differs in "
00342 "rdataset, adjusting "
00343 "%lu -> %lu",
00344 namebuf, typebuf, classbuf,
00345 (unsigned long) t->ttl,
00346 (unsigned long) rdl.ttl);
00347 }
00348 ISC_LIST_APPEND(rdl.rdata, &t->rdata, link);
00349 t = ISC_LIST_NEXT(t, link);
00350 }
00351
00352
00353
00354
00355 dns_rdataset_init(&rds);
00356 dns_rdataset_init(&ardataset);
00357 CHECK(dns_rdatalist_tordataset(&rdl, &rds));
00358 rds.trust = dns_trust_ultimate;
00359
00360
00361
00362
00363 switch (op) {
00364 case DNS_DIFFOP_ADD:
00365 case DNS_DIFFOP_ADDRESIGN:
00366 options = DNS_DBADD_MERGE | DNS_DBADD_EXACT |
00367 DNS_DBADD_EXACTTTL;
00368 result = dns_db_addrdataset(db, node, ver,
00369 0, &rds, options,
00370 &ardataset);
00371 break;
00372 case DNS_DIFFOP_DEL:
00373 case DNS_DIFFOP_DELRESIGN:
00374 options = DNS_DBSUB_EXACT | DNS_DBSUB_WANTOLD;
00375 result = dns_db_subtractrdataset(db, node, ver,
00376 &rds, options,
00377 &ardataset);
00378 break;
00379 default:
00380 INSIST(0);
00381 }
00382
00383 if (result == ISC_R_SUCCESS) {
00384 if (rds.type == dns_rdatatype_rrsig &&
00385 (op == DNS_DIFFOP_DELRESIGN ||
00386 op == DNS_DIFFOP_ADDRESIGN)) {
00387 isc_stdtime_t resign;
00388 resign = setresign(&ardataset);
00389 dns_db_setsigningtime(db, &ardataset,
00390 resign);
00391 }
00392 if (op == DNS_DIFFOP_ADD ||
00393 op == DNS_DIFFOP_ADDRESIGN)
00394 setownercase(&ardataset, name);
00395 if (op == DNS_DIFFOP_DEL ||
00396 op == DNS_DIFFOP_DELRESIGN)
00397 getownercase(&ardataset, name);
00398 } else if (result == DNS_R_UNCHANGED) {
00399
00400
00401
00402
00403
00404
00405
00406
00407 if (warn) {
00408 dns_name_format(dns_db_origin(db),
00409 namebuf,
00410 sizeof(namebuf));
00411 dns_rdataclass_format(dns_db_class(db),
00412 classbuf,
00413 sizeof(classbuf));
00414 isc_log_write(DIFF_COMMON_LOGARGS,
00415 ISC_LOG_WARNING,
00416 "%s/%s: dns_diff_apply: "
00417 "update with no effect",
00418 namebuf, classbuf);
00419 }
00420 if (op == DNS_DIFFOP_ADD ||
00421 op == DNS_DIFFOP_ADDRESIGN)
00422 setownercase(&ardataset, name);
00423 if (op == DNS_DIFFOP_DEL ||
00424 op == DNS_DIFFOP_DELRESIGN)
00425 getownercase(&ardataset, name);
00426 } else if (result == DNS_R_NXRRSET) {
00427
00428
00429
00430 if (op == DNS_DIFFOP_DEL ||
00431 op == DNS_DIFFOP_DELRESIGN)
00432 getownercase(&ardataset, name);
00433 if (dns_rdataset_isassociated(&ardataset))
00434 dns_rdataset_disassociate(&ardataset);
00435 } else {
00436 if (dns_rdataset_isassociated(&ardataset))
00437 dns_rdataset_disassociate(&ardataset);
00438 CHECK(result);
00439 }
00440 dns_db_detachnode(db, &node);
00441 if (dns_rdataset_isassociated(&ardataset))
00442 dns_rdataset_disassociate(&ardataset);
00443 }
00444 }
00445 return (ISC_R_SUCCESS);
00446
00447 failure:
00448 if (node != NULL)
00449 dns_db_detachnode(db, &node);
00450 return (result);
00451 }
00452
00453 isc_result_t
00454 dns_diff_apply(dns_diff_t *diff, dns_db_t *db, dns_dbversion_t *ver) {
00455 return (diff_apply(diff, db, ver, ISC_TRUE));
00456 }
00457
00458 isc_result_t
00459 dns_diff_applysilently(dns_diff_t *diff, dns_db_t *db, dns_dbversion_t *ver) {
00460 return (diff_apply(diff, db, ver, ISC_FALSE));
00461 }
00462
00463
00464
00465 isc_result_t
00466 dns_diff_load(dns_diff_t *diff, dns_addrdatasetfunc_t addfunc,
00467 void *add_private)
00468 {
00469 dns_difftuple_t *t;
00470 isc_result_t result;
00471
00472 REQUIRE(DNS_DIFF_VALID(diff));
00473
00474 t = ISC_LIST_HEAD(diff->tuples);
00475 while (t != NULL) {
00476 dns_name_t *name;
00477
00478 name = &t->name;
00479 while (t != NULL && dns_name_equal(&t->name, name)) {
00480 dns_rdatatype_t type, covers;
00481 dns_diffop_t op;
00482 dns_rdatalist_t rdl;
00483 dns_rdataset_t rds;
00484
00485 op = t->op;
00486 type = t->rdata.type;
00487 covers = rdata_covers(&t->rdata);
00488
00489 dns_rdatalist_init(&rdl);
00490 rdl.type = type;
00491 rdl.covers = covers;
00492 rdl.rdclass = t->rdata.rdclass;
00493 rdl.ttl = t->ttl;
00494
00495 while (t != NULL && dns_name_equal(&t->name, name) &&
00496 t->op == op && t->rdata.type == type &&
00497 rdata_covers(&t->rdata) == covers)
00498 {
00499 ISC_LIST_APPEND(rdl.rdata, &t->rdata, link);
00500 t = ISC_LIST_NEXT(t, link);
00501 }
00502
00503
00504
00505
00506 dns_rdataset_init(&rds);
00507 CHECK(dns_rdatalist_tordataset(&rdl, &rds));
00508 rds.trust = dns_trust_ultimate;
00509
00510 INSIST(op == DNS_DIFFOP_ADD);
00511 result = (*addfunc)(add_private, name, &rds);
00512 if (result == DNS_R_UNCHANGED) {
00513 isc_log_write(DIFF_COMMON_LOGARGS,
00514 ISC_LOG_WARNING,
00515 "dns_diff_load: "
00516 "update with no effect");
00517 } else if (result == ISC_R_SUCCESS ||
00518 result == DNS_R_NXRRSET) {
00519
00520
00521
00522 } else {
00523 CHECK(result);
00524 }
00525 }
00526 }
00527 result = ISC_R_SUCCESS;
00528 failure:
00529 return (result);
00530 }
00531
00532
00533
00534
00535
00536 isc_result_t
00537 dns_diff_sort(dns_diff_t *diff, dns_diff_compare_func *compare) {
00538 unsigned int length = 0;
00539 unsigned int i;
00540 dns_difftuple_t **v;
00541 dns_difftuple_t *p;
00542 REQUIRE(DNS_DIFF_VALID(diff));
00543
00544 for (p = ISC_LIST_HEAD(diff->tuples);
00545 p != NULL;
00546 p = ISC_LIST_NEXT(p, link))
00547 length++;
00548 if (length == 0)
00549 return (ISC_R_SUCCESS);
00550 v = isc_mem_get(diff->mctx, length * sizeof(dns_difftuple_t *));
00551 if (v == NULL)
00552 return (ISC_R_NOMEMORY);
00553 for (i = 0; i < length; i++) {
00554 p = ISC_LIST_HEAD(diff->tuples);
00555 v[i] = p;
00556 ISC_LIST_UNLINK(diff->tuples, p, link);
00557 }
00558 INSIST(ISC_LIST_HEAD(diff->tuples) == NULL);
00559 qsort(v, length, sizeof(v[0]), compare);
00560 for (i = 0; i < length; i++) {
00561 ISC_LIST_APPEND(diff->tuples, v[i], link);
00562 }
00563 isc_mem_put(diff->mctx, v, length * sizeof(dns_difftuple_t *));
00564 return (ISC_R_SUCCESS);
00565 }
00566
00567
00568
00569
00570
00571
00572
00573
00574 static isc_result_t
00575 diff_tuple_tordataset(dns_difftuple_t *t, dns_rdata_t *rdata,
00576 dns_rdatalist_t *rdl, dns_rdataset_t *rds)
00577 {
00578 REQUIRE(DNS_DIFFTUPLE_VALID(t));
00579 REQUIRE(rdl != NULL);
00580 REQUIRE(rds != NULL);
00581
00582 dns_rdatalist_init(rdl);
00583 rdl->type = t->rdata.type;
00584 rdl->rdclass = t->rdata.rdclass;
00585 rdl->ttl = t->ttl;
00586 dns_rdataset_init(rds);
00587 ISC_LINK_INIT(rdata, link);
00588 dns_rdata_clone(&t->rdata, rdata);
00589 ISC_LIST_APPEND(rdl->rdata, rdata, link);
00590 return (dns_rdatalist_tordataset(rdl, rds));
00591 }
00592
00593 isc_result_t
00594 dns_diff_print(dns_diff_t *diff, FILE *file) {
00595 isc_result_t result;
00596 dns_difftuple_t *t;
00597 char *mem = NULL;
00598 unsigned int size = 2048;
00599 const char *op = NULL;
00600
00601 REQUIRE(DNS_DIFF_VALID(diff));
00602
00603 mem = isc_mem_get(diff->mctx, size);
00604 if (mem == NULL)
00605 return (ISC_R_NOMEMORY);
00606
00607 for (t = ISC_LIST_HEAD(diff->tuples); t != NULL;
00608 t = ISC_LIST_NEXT(t, link))
00609 {
00610 isc_buffer_t buf;
00611 isc_region_t r;
00612
00613 dns_rdatalist_t rdl;
00614 dns_rdataset_t rds;
00615 dns_rdata_t rd = DNS_RDATA_INIT;
00616
00617 result = diff_tuple_tordataset(t, &rd, &rdl, &rds);
00618 if (result != ISC_R_SUCCESS) {
00619 UNEXPECTED_ERROR(__FILE__, __LINE__,
00620 "diff_tuple_tordataset failed: %s",
00621 dns_result_totext(result));
00622 result = ISC_R_UNEXPECTED;
00623 goto cleanup;
00624 }
00625 again:
00626 isc_buffer_init(&buf, mem, size);
00627 result = dns_rdataset_totext(&rds, &t->name,
00628 ISC_FALSE, ISC_FALSE, &buf);
00629
00630 if (result == ISC_R_NOSPACE) {
00631 isc_mem_put(diff->mctx, mem, size);
00632 size += 1024;
00633 mem = isc_mem_get(diff->mctx, size);
00634 if (mem == NULL) {
00635 result = ISC_R_NOMEMORY;
00636 goto cleanup;
00637 }
00638 goto again;
00639 }
00640
00641 if (result != ISC_R_SUCCESS)
00642 goto cleanup;
00643
00644
00645
00646 INSIST(buf.used >= 1 &&
00647 ((char *) buf.base)[buf.used-1] == '\n');
00648 buf.used--;
00649
00650 isc_buffer_usedregion(&buf, &r);
00651 switch (t->op) {
00652 case DNS_DIFFOP_EXISTS: op = "exists"; break;
00653 case DNS_DIFFOP_ADD: op = "add"; break;
00654 case DNS_DIFFOP_DEL: op = "del"; break;
00655 case DNS_DIFFOP_ADDRESIGN: op = "add re-sign"; break;
00656 case DNS_DIFFOP_DELRESIGN: op = "del re-sign"; break;
00657 }
00658 if (file != NULL)
00659 fprintf(file, "%s %.*s\n", op, (int) r.length,
00660 (char *) r.base);
00661 else
00662 isc_log_write(DIFF_COMMON_LOGARGS, ISC_LOG_DEBUG(7),
00663 "%s %.*s", op, (int) r.length,
00664 (char *) r.base);
00665 }
00666 result = ISC_R_SUCCESS;
00667 cleanup:
00668 if (mem != NULL)
00669 isc_mem_put(diff->mctx, mem, size);
00670 return (result);
00671 }