1/* $NetBSD$ */ 2 3/* 4 * Copyright (C) 2011, 2012 Internet Systems Consortium, Inc. ("ISC") 5 * 6 * Permission to use, copy, modify, and/or distribute this software for any 7 * purpose with or without fee is hereby granted, provided that the above 8 * copyright notice and this permission notice appear in all copies. 9 * 10 * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH 11 * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY 12 * AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT, 13 * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM 14 * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE 15 * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR 16 * PERFORMANCE OF THIS SOFTWARE. 17 */ 18 19/* Id */ 20 21/*! \file */ 22 23#include <config.h> 24 25#include <atf-c.h> 26 27#include <unistd.h> 28 29#include <dns/cache.h> 30#include <dns/callbacks.h> 31#include <dns/db.h> 32#include <dns/master.h> 33#include <dns/masterdump.h> 34#include <dns/name.h> 35#include <dns/rdata.h> 36#include <dns/rdatalist.h> 37#include <dns/rdataset.h> 38 39#include "dnstest.h" 40 41/* 42 * Helper functions 43 */ 44 45#define BUFLEN 255 46#define BIGBUFLEN (70 * 1024) 47#define TEST_ORIGIN "test" 48 49static dns_masterrawheader_t header; 50static isc_boolean_t headerset; 51 52static isc_result_t 53add_callback(void *arg, dns_name_t *owner, dns_rdataset_t *dataset); 54 55static void 56rawdata_callback(dns_zone_t *zone, dns_masterrawheader_t *header); 57 58static isc_result_t 59add_callback(void *arg, dns_name_t *owner, dns_rdataset_t *dataset) { 60 char buf[BIGBUFLEN]; 61 isc_buffer_t target; 62 isc_result_t result; 63 64 UNUSED(arg); 65 66 isc_buffer_init(&target, buf, BIGBUFLEN); 67 result = dns_rdataset_totext(dataset, owner, ISC_FALSE, ISC_FALSE, 68 &target); 69 return(result); 70} 71 72static void 73rawdata_callback(dns_zone_t *zone, dns_masterrawheader_t *h) { 74 UNUSED(zone); 75 header = *h; 76 headerset = ISC_TRUE; 77} 78 79static int 80test_master(const char *testfile, dns_masterformat_t format) { 81 isc_result_t result; 82 int len; 83 char origin[sizeof(TEST_ORIGIN)]; 84 dns_name_t dns_origin; 85 isc_buffer_t source; 86 isc_buffer_t target; 87 unsigned char name_buf[BUFLEN]; 88 dns_rdatacallbacks_t callbacks; 89 90 strcpy(origin, TEST_ORIGIN); 91 len = strlen(origin); 92 isc_buffer_init(&source, origin, len); 93 isc_buffer_add(&source, len); 94 isc_buffer_setactive(&source, len); 95 isc_buffer_init(&target, name_buf, BUFLEN); 96 dns_name_init(&dns_origin, NULL); 97 dns_master_initrawheader(&header); 98 99 result = dns_name_fromtext(&dns_origin, &source, dns_rootname, 100 0, &target); 101 if (result != ISC_R_SUCCESS) 102 return(result); 103 104 dns_rdatacallbacks_init_stdio(&callbacks); 105 callbacks.add = add_callback; 106 callbacks.rawdata = rawdata_callback; 107 callbacks.zone = NULL; 108 headerset = ISC_FALSE; 109 result = dns_master_loadfile2(testfile, &dns_origin, &dns_origin, 110 dns_rdataclass_in, ISC_TRUE, 111 &callbacks, mctx, format); 112 return (result); 113} 114 115/* 116 * Individual unit tests 117 */ 118 119/* Successful load test */ 120ATF_TC(load); 121ATF_TC_HEAD(load, tc) { 122 atf_tc_set_md_var(tc, "descr", "dns_master_loadfile() loads a " 123 "valid master file and returns success"); 124} 125ATF_TC_BODY(load, tc) { 126 isc_result_t result; 127 128 UNUSED(tc); 129 130 result = dns_test_begin(NULL, ISC_FALSE); 131 ATF_REQUIRE_EQ(result, ISC_R_SUCCESS); 132 133 result = test_master("testdata/master/master1.data", 134 dns_masterformat_text); 135 ATF_REQUIRE_EQ(result, ISC_R_SUCCESS); 136 137 dns_test_end(); 138} 139 140 141/* Unepxected end of file test */ 142ATF_TC(unexpected); 143ATF_TC_HEAD(unexpected, tc) { 144 atf_tc_set_md_var(tc, "descr", "dns_master_loadfile() returns " 145 "DNS_R_UNEXPECTED when file ends " 146 "too soon"); 147} 148ATF_TC_BODY(unexpected, tc) { 149 isc_result_t result; 150 151 UNUSED(tc); 152 153 result = dns_test_begin(NULL, ISC_FALSE); 154 ATF_REQUIRE_EQ(result, ISC_R_SUCCESS); 155 156 result = test_master("testdata/master/master2.data", 157 dns_masterformat_text); 158 ATF_REQUIRE_EQ(result, ISC_R_UNEXPECTEDEND); 159 160 dns_test_end(); 161} 162 163 164/* No owner test */ 165ATF_TC(noowner); 166ATF_TC_HEAD(noowner, tc) { 167 atf_tc_set_md_var(tc, "descr", "dns_master_loadfile() accepts broken " 168 "zones with no TTL for first record " 169 "if it is an SOA"); 170} 171ATF_TC_BODY(noowner, tc) { 172 isc_result_t result; 173 174 UNUSED(tc); 175 176 result = dns_test_begin(NULL, ISC_FALSE); 177 ATF_REQUIRE_EQ(result, ISC_R_SUCCESS); 178 179 result = test_master("testdata/master/master3.data", 180 dns_masterformat_text); 181 ATF_REQUIRE_EQ(result, DNS_R_NOOWNER); 182 183 dns_test_end(); 184} 185 186 187/* No TTL test */ 188ATF_TC(nottl); 189ATF_TC_HEAD(nottl, tc) { 190 atf_tc_set_md_var(tc, "descr", "dns_master_loadfile() returns " 191 "DNS_R_NOOWNER when no owner name " 192 "is specified"); 193} 194 195ATF_TC_BODY(nottl, tc) { 196 isc_result_t result; 197 198 UNUSED(tc); 199 200 result = dns_test_begin(NULL, ISC_FALSE); 201 ATF_REQUIRE_EQ(result, ISC_R_SUCCESS); 202 203 result = test_master("testdata/master/master4.data", 204 dns_masterformat_text); 205 ATF_REQUIRE_EQ(result, ISC_R_SUCCESS); 206 207 dns_test_end(); 208} 209 210 211/* Bad class test */ 212ATF_TC(badclass); 213ATF_TC_HEAD(badclass, tc) { 214 atf_tc_set_md_var(tc, "descr", "dns_master_loadfile() returns " 215 "DNS_R_BADCLASS when record class " 216 "doesn't match zone class"); 217} 218ATF_TC_BODY(badclass, tc) { 219 isc_result_t result; 220 221 UNUSED(tc); 222 223 result = dns_test_begin(NULL, ISC_FALSE); 224 ATF_REQUIRE_EQ(result, ISC_R_SUCCESS); 225 226 result = test_master("testdata/master/master5.data", 227 dns_masterformat_text); 228 ATF_REQUIRE_EQ(result, DNS_R_BADCLASS); 229 230 dns_test_end(); 231} 232 233/* Too big rdata test */ 234ATF_TC(toobig); 235ATF_TC_HEAD(toobig, tc) { 236 atf_tc_set_md_var(tc, "descr", "dns_master_loadfile() returns " 237 "ISC_R_NOSPACE when record is too big"); 238} 239ATF_TC_BODY(toobig, tc) { 240 isc_result_t result; 241 242 UNUSED(tc); 243 244 result = dns_test_begin(NULL, ISC_FALSE); 245 ATF_REQUIRE_EQ(result, ISC_R_SUCCESS); 246 247 result = test_master("testdata/master/master15.data", 248 dns_masterformat_text); 249 ATF_REQUIRE_EQ(result, ISC_R_NOSPACE); 250 251 dns_test_end(); 252} 253 254/* Maximum rdata test */ 255ATF_TC(maxrdata); 256ATF_TC_HEAD(maxrdata, tc) { 257 atf_tc_set_md_var(tc, "descr", "dns_master_loadfile() returns " 258 "ISC_R_SUCCESS when record is maximum " 259 "size"); 260} 261ATF_TC_BODY(maxrdata, tc) { 262 isc_result_t result; 263 264 UNUSED(tc); 265 266 result = dns_test_begin(NULL, ISC_FALSE); 267 ATF_REQUIRE_EQ(result, ISC_R_SUCCESS); 268 269 result = test_master("testdata/master/master16.data", 270 dns_masterformat_text); 271 ATF_REQUIRE_EQ(result, ISC_R_SUCCESS); 272 273 dns_test_end(); 274} 275 276/* DNSKEY test */ 277ATF_TC(dnskey); 278ATF_TC_HEAD(dnskey, tc) { 279 atf_tc_set_md_var(tc, "descr", "dns_master_loadfile() understands " 280 "DNSKEY with key material"); 281} 282ATF_TC_BODY(dnskey, tc) { 283 isc_result_t result; 284 285 UNUSED(tc); 286 287 result = dns_test_begin(NULL, ISC_FALSE); 288 ATF_REQUIRE_EQ(result, ISC_R_SUCCESS); 289 290 result = test_master("testdata/master/master6.data", 291 dns_masterformat_text); 292 ATF_REQUIRE_EQ(result, ISC_R_SUCCESS); 293 294 dns_test_end(); 295} 296 297 298/* DNSKEY with no key material test */ 299ATF_TC(dnsnokey); 300ATF_TC_HEAD(dnsnokey, tc) { 301 atf_tc_set_md_var(tc, "descr", "dns_master_loadfile() understands " 302 "DNSKEY with no key material"); 303} 304ATF_TC_BODY(dnsnokey, tc) { 305 isc_result_t result; 306 307 UNUSED(tc); 308 309 result = dns_test_begin(NULL, ISC_FALSE); 310 ATF_REQUIRE_EQ(result, ISC_R_SUCCESS); 311 312 result = test_master("testdata/master/master7.data", 313 dns_masterformat_text); 314 ATF_REQUIRE_EQ(result, ISC_R_SUCCESS); 315 316 dns_test_end(); 317} 318 319/* Include test */ 320ATF_TC(include); 321ATF_TC_HEAD(include, tc) { 322 atf_tc_set_md_var(tc, "descr", "dns_master_loadfile() understands " 323 "$INCLUDE"); 324} 325ATF_TC_BODY(include, tc) { 326 isc_result_t result; 327 328 UNUSED(tc); 329 330 result = dns_test_begin(NULL, ISC_FALSE); 331 ATF_REQUIRE_EQ(result, ISC_R_SUCCESS); 332 333 result = test_master("testdata/master/master8.data", 334 dns_masterformat_text); 335 ATF_REQUIRE_EQ(result, DNS_R_SEENINCLUDE); 336 337 dns_test_end(); 338} 339 340/* Include failure test */ 341ATF_TC(includefail); 342ATF_TC_HEAD(includefail, tc) { 343 atf_tc_set_md_var(tc, "descr", "dns_master_loadfile() understands " 344 "$INCLUDE failures"); 345} 346ATF_TC_BODY(includefail, tc) { 347 isc_result_t result; 348 349 UNUSED(tc); 350 351 result = dns_test_begin(NULL, ISC_FALSE); 352 ATF_REQUIRE_EQ(result, ISC_R_SUCCESS); 353 354 result = test_master("testdata/master/master9.data", 355 dns_masterformat_text); 356 ATF_REQUIRE_EQ(result, DNS_R_BADCLASS); 357 358 dns_test_end(); 359} 360 361 362/* Non-empty blank lines test */ 363ATF_TC(blanklines); 364ATF_TC_HEAD(blanklines, tc) { 365 atf_tc_set_md_var(tc, "descr", "dns_master_loadfile() handles " 366 "non-empty blank lines"); 367} 368ATF_TC_BODY(blanklines, tc) { 369 isc_result_t result; 370 371 UNUSED(tc); 372 373 result = dns_test_begin(NULL, ISC_FALSE); 374 ATF_REQUIRE_EQ(result, ISC_R_SUCCESS); 375 376 result = test_master("testdata/master/master10.data", 377 dns_masterformat_text); 378 ATF_REQUIRE_EQ(result, ISC_R_SUCCESS); 379 380 dns_test_end(); 381} 382 383/* SOA leading zeroes test */ 384ATF_TC(leadingzero); 385ATF_TC_HEAD(leadingzero, tc) { 386 atf_tc_set_md_var(tc, "descr", "dns_master_loadfile() allows " 387 "leading zeroes in SOA"); 388} 389ATF_TC_BODY(leadingzero, tc) { 390 isc_result_t result; 391 392 UNUSED(tc); 393 394 result = dns_test_begin(NULL, ISC_FALSE); 395 ATF_REQUIRE_EQ(result, ISC_R_SUCCESS); 396 397 result = test_master("testdata/master/master11.data", 398 dns_masterformat_text); 399 ATF_REQUIRE_EQ(result, ISC_R_SUCCESS); 400 401 dns_test_end(); 402} 403 404ATF_TC(totext); 405ATF_TC_HEAD(totext, tc) { 406 atf_tc_set_md_var(tc, "descr", "masterfile totext tests"); 407} 408ATF_TC_BODY(totext, tc) { 409 isc_result_t result; 410 dns_rdataset_t rdataset; 411 dns_rdatalist_t rdatalist; 412 isc_buffer_t target; 413 unsigned char buf[BIGBUFLEN]; 414 415 UNUSED(tc); 416 417 result = dns_test_begin(NULL, ISC_FALSE); 418 ATF_REQUIRE_EQ(result, ISC_R_SUCCESS); 419 420 /* First, test with an empty rdataset */ 421 rdatalist.rdclass = dns_rdataclass_in; 422 rdatalist.type = dns_rdatatype_none; 423 rdatalist.covers = dns_rdatatype_none; 424 rdatalist.ttl = 0; 425 ISC_LIST_INIT(rdatalist.rdata); 426 ISC_LINK_INIT(&rdatalist, link); 427 428 dns_rdataset_init(&rdataset); 429 result = dns_rdatalist_tordataset(&rdatalist, &rdataset); 430 ATF_CHECK_EQ(result, ISC_R_SUCCESS); 431 432 isc_buffer_init(&target, buf, BIGBUFLEN); 433 result = dns_master_rdatasettotext(dns_rootname, 434 &rdataset, &dns_master_style_debug, 435 &target); 436 ATF_CHECK_EQ(result, ISC_R_SUCCESS); 437 ATF_CHECK_EQ(isc_buffer_usedlength(&target), 0); 438 439 /* 440 * XXX: We will also need to add tests for dumping various 441 * rdata types, classes, etc, and comparing the results against 442 * known-good output. 443 */ 444 445 dns_test_end(); 446} 447 448/* Raw load */ 449ATF_TC(loadraw); 450ATF_TC_HEAD(loadraw, tc) { 451 atf_tc_set_md_var(tc, "descr", "dns_master_loadfile() loads a " 452 "valid raw file and returns success"); 453} 454ATF_TC_BODY(loadraw, tc) { 455 isc_result_t result; 456 457 UNUSED(tc); 458 459 result = dns_test_begin(NULL, ISC_FALSE); 460 ATF_REQUIRE_EQ(result, ISC_R_SUCCESS); 461 462 /* Raw format version 0 */ 463 result = test_master("testdata/master/master12.data", 464 dns_masterformat_raw); 465 ATF_CHECK_STREQ(isc_result_totext(result), "success"); 466 ATF_CHECK(headerset); 467 ATF_CHECK_EQ(header.flags, 0); 468 469 /* Raw format version 1, no source serial */ 470 result = test_master("testdata/master/master13.data", 471 dns_masterformat_raw); 472 ATF_CHECK_STREQ(isc_result_totext(result), "success"); 473 ATF_CHECK(headerset); 474 ATF_CHECK_EQ(header.flags, 0); 475 476 /* Raw format version 1, source serial == 2011120101 */ 477 result = test_master("testdata/master/master14.data", 478 dns_masterformat_raw); 479 ATF_CHECK_STREQ(isc_result_totext(result), "success"); 480 ATF_CHECK(headerset); 481 ATF_CHECK((header.flags & DNS_MASTERRAW_SOURCESERIALSET) != 0); 482 ATF_CHECK_EQ(header.sourceserial, 2011120101); 483 484 dns_test_end(); 485} 486 487/* Raw dump*/ 488ATF_TC(dumpraw); 489ATF_TC_HEAD(dumpraw, tc) { 490 atf_tc_set_md_var(tc, "descr", "dns_master_dump*() functions " 491 "dump valid raw files"); 492} 493ATF_TC_BODY(dumpraw, tc) { 494 isc_result_t result; 495 dns_db_t *db = NULL; 496 dns_dbversion_t *version = NULL; 497 char origin[sizeof(TEST_ORIGIN)]; 498 dns_name_t dns_origin; 499 isc_buffer_t source, target; 500 unsigned char name_buf[BUFLEN]; 501 int len; 502 503 UNUSED(tc); 504 505 strcpy(origin, TEST_ORIGIN); 506 len = strlen(origin); 507 isc_buffer_init(&source, origin, len); 508 isc_buffer_add(&source, len); 509 isc_buffer_setactive(&source, len); 510 isc_buffer_init(&target, name_buf, BUFLEN); 511 dns_name_init(&dns_origin, NULL); 512 result = dns_name_fromtext(&dns_origin, &source, dns_rootname, 513 0, &target); 514 ATF_REQUIRE_EQ(result, ISC_R_SUCCESS); 515 516 result = dns_test_begin(NULL, ISC_FALSE); 517 ATF_REQUIRE_EQ(result, ISC_R_SUCCESS); 518 519 result = dns_db_create(mctx, "rbt", &dns_origin, dns_dbtype_zone, 520 dns_rdataclass_in, 0, NULL, &db); 521 ATF_REQUIRE_EQ(result, ISC_R_SUCCESS); 522 523 result = dns_db_load(db, "testdata/master/master1.data"); 524 ATF_REQUIRE_EQ(result, ISC_R_SUCCESS); 525 526 dns_db_currentversion(db, &version); 527 528 result = dns_master_dump2(mctx, db, version, 529 &dns_master_style_default, "test.dump", 530 dns_masterformat_raw); 531 ATF_REQUIRE_EQ(result, ISC_R_SUCCESS); 532 533 result = test_master("test.dump", dns_masterformat_raw); 534 ATF_CHECK_STREQ(isc_result_totext(result), "success"); 535 ATF_CHECK(headerset); 536 ATF_CHECK_EQ(header.flags, 0); 537 538 dns_master_initrawheader(&header); 539 header.sourceserial = 12345; 540 header.flags |= DNS_MASTERRAW_SOURCESERIALSET; 541 542 unlink("test.dump"); 543 result = dns_master_dump3(mctx, db, version, 544 &dns_master_style_default, "test.dump", 545 dns_masterformat_raw, &header); 546 ATF_REQUIRE_EQ(result, ISC_R_SUCCESS); 547 548 result = test_master("test.dump", dns_masterformat_raw); 549 ATF_CHECK_STREQ(isc_result_totext(result), "success"); 550 ATF_CHECK(headerset); 551 ATF_CHECK((header.flags & DNS_MASTERRAW_SOURCESERIALSET) != 0); 552 ATF_CHECK_EQ(header.sourceserial, 12345); 553 554 unlink("test.dump"); 555 dns_db_closeversion(db, &version, ISC_FALSE); 556 dns_db_detach(&db); 557 dns_test_end(); 558} 559 560/* 561 * Main 562 */ 563ATF_TP_ADD_TCS(tp) { 564 ATF_TP_ADD_TC(tp, load); 565 ATF_TP_ADD_TC(tp, unexpected); 566 ATF_TP_ADD_TC(tp, noowner); 567 ATF_TP_ADD_TC(tp, nottl); 568 ATF_TP_ADD_TC(tp, badclass); 569 ATF_TP_ADD_TC(tp, dnskey); 570 ATF_TP_ADD_TC(tp, dnsnokey); 571 ATF_TP_ADD_TC(tp, include); 572 ATF_TP_ADD_TC(tp, includefail); 573 ATF_TP_ADD_TC(tp, blanklines); 574 ATF_TP_ADD_TC(tp, leadingzero); 575 ATF_TP_ADD_TC(tp, totext); 576 ATF_TP_ADD_TC(tp, loadraw); 577 ATF_TP_ADD_TC(tp, dumpraw); 578 ATF_TP_ADD_TC(tp, toobig); 579 ATF_TP_ADD_TC(tp, maxrdata); 580 581 return (atf_no_error()); 582} 583 584