Commit 08f84c8f authored by Evan Hunt's avatar Evan Hunt
Browse files

Merge branch '135-add-basic-unit-tests-for-update_sigs' into 'v9_9'

Add basic unit tests for update_sigs()

Closes #135

See merge request !112
parents a1e27966 dfe3c55e
Pipeline #1578 failed with stages
in 5 minutes and 57 seconds
4939. [test] Add basic unit tests for update_sigs(). [GL #135]
4933. [bug] Not creating signing keys for an inline signed zone
prevented changes applied to the raw zone from being
reflected in the secure zone until signing keys were
......
......@@ -17,6 +17,7 @@ tp: private_test
tp: rdata_test
tp: rdataset_test
tp: resolver_test
tp: sigs_test
tp: time_test
tp: tsig_test
tp: update_test
......
......@@ -16,6 +16,7 @@ atf_test_program{name='private_test'}
atf_test_program{name='rdata_test'}
atf_test_program{name='rdataset_test'}
atf_test_program{name='resolver_test'}
atf_test_program{name='sigs_test'}
atf_test_program{name='time_test'}
atf_test_program{name='tsig_test'}
atf_test_program{name='update_test'}
......
......@@ -51,6 +51,7 @@ SRCS = acl_test.c \
rdata_test.c \
rdataset_test.c \
resolver_test.c \
sigs_test.c \
time_test.c \
tsig_test.c \
update_test.c \
......@@ -74,6 +75,7 @@ TARGETS = acl_test@EXEEXT@ \
rdata_test@EXEEXT@ \
rdataset_test@EXEEXT@ \
resolver_test@EXEEXT@ \
sigs_test@EXEEXT@ \
time_test@EXEEXT@ \
tsig_test@EXEEXT@ \
update_test@EXEEXT@ \
......@@ -176,6 +178,11 @@ dispatch_test@EXEEXT@: dispatch_test.@O@ dnstest.@O@ ${ISCDEPLIBS} ${DNSDEPLIBS}
dispatch_test.@O@ dnstest.@O@ ${DNSLIBS} \
${ISCLIBS} ${LIBS}
sigs_test@EXEEXT@: sigs_test.@O@ dnstest.@O@ ${ISCDEPLIBS} ${DNSDEPLIBS}
${LIBTOOL_MODE_LINK} ${PURIFY} ${CC} ${CFLAGS} ${LDFLAGS} -o $@ \
sigs_test.@O@ dnstest.@O@ ${DNSLIBS} \
${ISCLIBS} ${LIBS}
db_test@EXEEXT@: db_test.@O@ ${ISCDEPLIBS} ${DNSDEPLIBS}
${LIBTOOL_MODE_LINK} ${PURIFY} ${CC} ${CFLAGS} ${LDFLAGS} -o $@ \
db_test.@O@ dnstest.@O@ ${DNSLIBS} \
......
......@@ -31,6 +31,7 @@
#include <isc/lex.h>
#include <isc/mem.h>
#include <isc/os.h>
#include <isc/stdio.h>
#include <isc/string.h>
#include <isc/socket.h>
#include <isc/task.h>
......@@ -41,6 +42,7 @@
#include <dns/fixedname.h>
#include <dns/log.h>
#include <dns/name.h>
#include <dns/rdatatype.h>
#include <dns/result.h>
#include <dns/view.h>
#include <dns/zone.h>
......@@ -210,58 +212,69 @@ dns_test_makeview(const char *name, dns_view_t **viewp) {
return (result);
}
/*
* Create a zone with origin 'name', return a pointer to the zone object in
* 'zonep'. If 'view' is set, add the zone to that view; otherwise, create
* a new view for the purpose.
*
* If the created view is going to be needed by the caller subsequently,
* then 'keepview' should be set to true; this will prevent the view
* from being detached. In this case, the caller is responsible for
* detaching the view.
*/
isc_result_t
dns_test_makezone(const char *name, dns_zone_t **zonep, dns_view_t *view,
isc_boolean_t keepview)
isc_boolean_t createview)
{
isc_result_t result;
dns_fixedname_t fixed_origin;
dns_zone_t *zone = NULL;
isc_buffer_t buffer;
dns_fixedname_t fixorigin;
isc_result_t result;
dns_name_t *origin;
if (view == NULL)
CHECK(dns_view_create(mctx, dns_rdataclass_in, "view", &view));
else if (!keepview)
keepview = ISC_TRUE;
zone = *zonep;
if (zone == NULL)
CHECK(dns_zone_create(&zone, mctx));
isc_buffer_constinit(&buffer, name, strlen(name));
isc_buffer_add(&buffer, strlen(name));
dns_fixedname_init(&fixorigin);
origin = dns_fixedname_name(&fixorigin);
CHECK(dns_name_fromtext(origin, &buffer, dns_rootname, 0, NULL));
CHECK(dns_zone_setorigin(zone, origin));
dns_zone_setview(zone, view);
REQUIRE(view == NULL || !createview);
/*
* Create the zone structure.
*/
result = dns_zone_create(&zone, mctx);
if (result != ISC_R_SUCCESS) {
return (result);
}
/*
* Set zone type and origin.
*/
dns_zone_settype(zone, dns_zone_master);
dns_zone_setclass(zone, view->rdclass);
dns_view_addzone(view, zone);
dns_fixedname_init(&fixed_origin);
origin = dns_fixedname_name(&fixed_origin);
result = dns_name_fromstring(origin, name, 0, NULL);
if (result != ISC_R_SUCCESS) {
goto detach_zone;
}
result = dns_zone_setorigin(zone, origin);
if (result != ISC_R_SUCCESS) {
goto detach_zone;
}
if (!keepview)
dns_view_detach(&view);
/*
* If requested, create a view.
*/
if (createview) {
result = dns_test_makeview("view", &view);
if (result != ISC_R_SUCCESS) {
goto detach_zone;
}
}
/*
* If a view was passed as an argument or created above, attach the
* created zone to it. Otherwise, set the zone's class to IN.
*/
if (view != NULL) {
dns_zone_setview(zone, view);
dns_zone_setclass(zone, view->rdclass);
dns_view_addzone(view, zone);
} else {
dns_zone_setclass(zone, dns_rdataclass_in);
}
*zonep = zone;
return (ISC_R_SUCCESS);
cleanup:
if (zone != NULL)
dns_zone_detach(&zone);
if (view != NULL)
dns_view_detach(&view);
detach_zone:
dns_zone_detach(&zone);
return (result);
}
......@@ -372,9 +385,9 @@ dns_test_tohex(const unsigned char *data, size_t len, char *buf, size_t buflen)
}
isc_result_t
dns_test_rdata_fromstring(dns_rdata_t *rdata, dns_rdataclass_t rdclass,
dns_rdatatype_t rdtype, unsigned char *dst,
size_t dstlen, const char *src)
dns_test_rdatafromstring(dns_rdata_t *rdata, dns_rdataclass_t rdclass,
dns_rdatatype_t rdtype, unsigned char *dst,
size_t dstlen, const char *src)
{
isc_buffer_t source, target;
isc_lex_t *lex = NULL;
......@@ -447,3 +460,73 @@ dns_test_namefromstring(const char *namestr, dns_fixedname_t *fname) {
isc_buffer_free(&b);
}
isc_result_t
dns_test_difffromchanges(dns_diff_t *diff, const zonechange_t *changes) {
isc_result_t result = ISC_R_SUCCESS;
unsigned char rdata_buf[1024];
dns_difftuple_t *tuple = NULL;
isc_consttextregion_t region;
dns_rdatatype_t rdatatype;
dns_fixedname_t fixedname;
dns_rdata_t rdata;
dns_name_t *name;
size_t i;
REQUIRE(diff != NULL);
REQUIRE(changes != NULL);
dns_diff_init(mctx, diff);
for (i = 0; changes[i].owner != NULL; i++) {
/*
* Parse owner name.
*/
dns_fixedname_init(&fixedname);
name = dns_fixedname_name(&fixedname);
result = dns_name_fromstring(name, changes[i].owner, 0, mctx);
if (result != ISC_R_SUCCESS) {
break;
}
/*
* Parse RDATA type.
*/
region.base = changes[i].type;
region.length = strlen(changes[i].type);
result = dns_rdatatype_fromtext(&rdatatype,
(isc_textregion_t *)&region);
if (result != ISC_R_SUCCESS) {
break;
}
/*
* Parse RDATA.
*/
dns_rdata_init(&rdata);
result = dns_test_rdatafromstring(&rdata, dns_rdataclass_in,
rdatatype, rdata_buf,
sizeof(rdata_buf),
changes[i].rdata);
if (result != ISC_R_SUCCESS) {
break;
}
/*
* Create a diff tuple for the parsed change and append it to
* the diff.
*/
result = dns_difftuple_create(mctx, changes[i].op, name,
changes[i].ttl, &rdata, &tuple);
if (result != ISC_R_SUCCESS) {
break;
}
dns_diff_append(diff, &tuple);
}
if (result != ISC_R_SUCCESS) {
dns_diff_clear(diff);
}
return (result);
}
......@@ -28,6 +28,7 @@
#include <isc/timer.h>
#include <isc/util.h>
#include <dns/diff.h>
#include <dns/result.h>
#include <dns/zone.h>
......@@ -38,6 +39,16 @@
goto cleanup; \
} while (0)
typedef struct {
dns_diffop_t op;
const char *owner;
dns_ttl_t ttl;
const char *type;
const char *rdata;
} zonechange_t;
#define ZONECHANGE_SENTINEL { 0, NULL, 0, NULL, NULL }
extern isc_mem_t *mctx;
extern isc_entropy_t *ectx;
extern isc_log_t *lctx;
......@@ -59,9 +70,25 @@ dns_test_end(void);
isc_result_t
dns_test_makeview(const char *name, dns_view_t **viewp);
/*%
* Create a zone with origin 'name', return a pointer to the zone object in
* 'zonep'.
*
* If 'view' is set, the returned zone will be assigned to the passed view.
* 'createview' must be set to false when 'view' is non-NULL.
*
* If 'view' is not set and 'createview' is true, a new view is also created
* and the returned zone is assigned to it. This imposes two requirements on
* the caller: 1) the returned zone has to be subsequently assigned to a zone
* manager, otherwise its cleanup will fail, 2) the created view has to be
* cleaned up by the caller.
*
* If 'view' is not set and 'createview' is false, the returned zone will not
* be assigned to any view.
*/
isc_result_t
dns_test_makezone(const char *name, dns_zone_t **zonep, dns_view_t *view,
isc_boolean_t keepview);
isc_boolean_t createview);
isc_result_t
dns_test_setupzonemgr(void);
......@@ -91,9 +118,16 @@ dns_test_tohex(const unsigned char *data, size_t len, char *buf, size_t buflen);
* uncompressed wire form of that RDATA at "dst", which is "dstlen" bytes long.
*/
isc_result_t
dns_test_rdata_fromstring(dns_rdata_t *rdata, dns_rdataclass_t rdclass,
dns_rdatatype_t rdtype, unsigned char *dst,
size_t dstlen, const char *src);
dns_test_rdatafromstring(dns_rdata_t *rdata, dns_rdataclass_t rdclass,
dns_rdatatype_t rdtype, unsigned char *dst,
size_t dstlen, const char *src);
void
dns_test_namefromstring(const char *namestr, dns_fixedname_t *fname);
/*%
* Given a pointer to an uninitialized dns_diff_t structure in 'diff', make it
* contain diff tuples representing zone database changes listed in 'changes'.
*/
isc_result_t
dns_test_difffromchanges(dns_diff_t *diff, const zonechange_t *changes);
......@@ -14,8 +14,6 @@
* PERFORMANCE OF THIS SOFTWARE.
*/
/* $Id$ */
/*! \file */
#include <config.h>
......@@ -80,10 +78,10 @@ nsec3param_salttotext_test(const nsec3param_salttotext_test_params_t *params) {
/*
* Prepare a dns_rdata_nsec3param_t structure for testing.
*/
result = dns_test_rdata_fromstring(&rdata, dns_rdataclass_in,
dns_rdatatype_nsec3param, buf,
sizeof(buf),
params->nsec3param_text);
result = dns_test_rdatafromstring(&rdata, dns_rdataclass_in,
dns_rdatatype_nsec3param, buf,
sizeof(buf),
params->nsec3param_text);
ATF_REQUIRE_EQ(result, ISC_R_SUCCESS);
result = dns_rdata_tostruct(&rdata, &nsec3param, NULL);
ATF_REQUIRE_EQ(result, ISC_R_SUCCESS);
......
......@@ -158,9 +158,9 @@ check_text_ok_single(const text_ok_t *text_ok, dns_rdataclass_t rdclass,
/*
* Try converting text form RDATA into uncompressed wire form.
*/
result = dns_test_rdata_fromstring(&rdata, rdclass, type, buf_fromtext,
sizeof(buf_fromtext),
text_ok->text_in);
result = dns_test_rdatafromstring(&rdata, rdclass, type, buf_fromtext,
sizeof(buf_fromtext),
text_ok->text_in);
/*
* Check whether result is as expected.
*/
......
/*
* Copyright (C) Internet Systems Consortium, Inc. ("ISC")
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
*
* See the COPYRIGHT file distributed with this work for additional
* information regarding copyright ownership.
*/
/*! \file */
#include <config.h>
#include <atf-c.h>
#include <dns/db.h>
#include <dns/dnssec.h>
#include <dns/rdatatype.h>
#include <dns/zone.h>
#include "../zone_p.h"
#include "dnstest.h"
/*%
* Structure characterizing a single diff tuple in the dns_diff_t structure
* prepared by dns__zone_updatesigs().
*/
typedef struct {
dns_diffop_t op;
const char *owner;
dns_ttl_t ttl;
const char *type;
} zonediff_t;
#define ZONEDIFF_SENTINEL { 0, NULL, 0, NULL }
/*%
* Structure defining a dns__zone_updatesigs() test.
*/
typedef struct {
const char *description; /* test description */
const zonechange_t *changes; /* array of "raw" zone changes */
const zonediff_t *zonediff; /* array of "processed" zone changes */
} updatesigs_test_params_t;
/*%
* Check whether the 'found' tuple matches the 'expected' tuple. 'found' is
* the 'index'th tuple output by dns__zone_updatesigs() in test 'test'.
*/
static void
compare_tuples(const zonediff_t *expected, dns_difftuple_t *found,
const updatesigs_test_params_t *test, size_t index)
{
char found_covers[DNS_RDATATYPE_FORMATSIZE] = { };
char found_type[DNS_RDATATYPE_FORMATSIZE] = { };
char found_name[DNS_NAME_FORMATSIZE];
isc_consttextregion_t typeregion;
dns_fixedname_t expected_fname;
dns_rdatatype_t expected_type;
dns_name_t *expected_name;
dns_rdata_rrsig_t rrsig;
isc_buffer_t typebuf;
isc_result_t result;
REQUIRE(expected != NULL);
REQUIRE(found != NULL);
REQUIRE(index > 0);
/*
* Check operation.
*/
ATF_CHECK_EQ_MSG(expected->op, found->op,
"test \"%s\": tuple %zu: "
"expected op %d, found %d",
test->description, index,
expected->op, found->op);
/*
* Check owner name.
*/
dns_fixedname_init(&expected_fname);
expected_name = dns_fixedname_name(&expected_fname);
result = dns_name_fromstring(expected_name, expected->owner, 0, mctx);
ATF_REQUIRE_EQ(result, ISC_R_SUCCESS);
dns_name_format(&found->name, found_name, sizeof(found_name));
ATF_CHECK_MSG(dns_name_equal(expected_name, &found->name),
"test \"%s\": tuple %zu: "
"expected owner \"%s\", found \"%s\"",
test->description, index,
expected->owner, found_name);
/*
* Check TTL.
*/
ATF_CHECK_EQ_MSG(expected->ttl, found->ttl,
"test \"%s\": tuple %zu: "
"expected TTL %u, found %u",
test->description, index,
expected->ttl, found->ttl);
/*
* Parse expected RR type.
*/
typeregion.base = expected->type;
typeregion.length = strlen(expected->type);
result = dns_rdatatype_fromtext(&expected_type,
(isc_textregion_t*)&typeregion);
ATF_REQUIRE_EQ(result, ISC_R_SUCCESS);
/*
* Format found RR type for reporting purposes.
*/
isc_buffer_init(&typebuf, found_type, sizeof(found_type));
result = dns_rdatatype_totext(found->rdata.type, &typebuf);
ATF_REQUIRE_EQ(result, ISC_R_SUCCESS);
/*
* Check RR type.
*/
switch (expected->op) {
case DNS_DIFFOP_ADDRESIGN:
case DNS_DIFFOP_DELRESIGN:
/*
* Found tuple must be of type RRSIG.
*/
ATF_CHECK_EQ_MSG(found->rdata.type, dns_rdatatype_rrsig,
"test \"%s\": tuple %zu: "
"expected type RRSIG, found %s",
test->description, index,
found_type);
if (found->rdata.type != dns_rdatatype_rrsig) {
break;
}
/*
* The signature must cover an RRset of type 'expected->type'.
*/
result = dns_rdata_tostruct(&found->rdata, &rrsig, NULL);
ATF_REQUIRE_EQ(result, ISC_R_SUCCESS);
isc_buffer_init(&typebuf, found_covers, sizeof(found_covers));
result = dns_rdatatype_totext(rrsig.covered, &typebuf);
ATF_REQUIRE_EQ(result, ISC_R_SUCCESS);
ATF_CHECK_EQ_MSG(expected_type, rrsig.covered,
"test \"%s\": tuple %zu: "
"expected RRSIG to cover %s, found covers %s",
test->description, index,
expected->type, found_covers);
break;
default:
/*
* Found tuple must be of type 'expected->type'.
*/
ATF_CHECK_EQ_MSG(expected_type, found->rdata.type,
"test \"%s\": tuple %zu: "
"expected type %s, found %s",
test->description, index,
expected->type, found_type);
break;
}
}
/*%
* Perform a single dns__zone_updatesigs() test defined in 'test'. All other
* arguments are expected to remain constant between subsequent invocations of
* this function.
*/
static void
updatesigs_test(const updatesigs_test_params_t *test, dns_zone_t *zone,
dns_db_t *db, dst_key_t *zone_keys[], unsigned int nkeys,
isc_stdtime_t now)
{
size_t tuples_expected, tuples_found, index;
dns_dbversion_t *version = NULL;
dns_diff_t raw_diff, zone_diff;
const zonediff_t *expected;
dns_difftuple_t *found;
isc_result_t result;
dns__zonediff_t zonediff = {
.diff = &zone_diff,
.offline = ISC_FALSE,
};
REQUIRE(test != NULL);
REQUIRE(test->description != NULL);
REQUIRE(test->changes != NULL);
REQUIRE(zone != NULL);
REQUIRE(db != NULL);
REQUIRE(zone_keys != NULL);
/*
* Create a new version of the zone's database.
*/
result = dns_db_newversion(db, &version);
ATF_REQUIRE_EQ(result, ISC_R_SUCCESS);
/*
* Create a diff representing the supplied changes.
*/
result = dns_test_difffromchanges(&raw_diff, test->changes);
ATF_REQUIRE_EQ(result, ISC_R_SUCCESS);
/*
* Apply the "raw" diff to the new version of the zone's database as
* this is what dns__zone_updatesigs() expects to happen before it is
* called.
*/
dns_diff_apply(&raw_diff, db, version);
/*
* Initialize the structure dns__zone_updatesigs() will modify.
*/
dns_diff_init(mctx, &zone_diff);
/*
* Check whether dns__zone_updatesigs() behaves as expected.
*/
result = dns__zone_updatesigs(&raw_diff, db, version, zone_keys, nkeys,
zone, now - 3600, now + 3600, now,
ISC_TRUE, ISC_FALSE, &zonediff);
ATF_CHECK_EQ_MSG(result, ISC_R_SUCCESS,
"test \"%s\": expected success, got %s",
test->description, isc_result_totext(result));
ATF_CHECK_MSG(ISC_LIST_EMPTY(raw_diff.tuples),
"test \"%s\": raw diff was not emptied",
test->description);
ATF_CHECK_MSG(!ISC_LIST_EMPTY(zone_diff.tuples),
"test \"%s\": zone diff was not created",
test->description);
/*
* Ensure that the number of tuples in the zone diff is as expected.
*/
tuples_expected = 0;
for (expected = test->zonediff;
expected->owner != NULL;
expected++)
{
tuples_expected++;
}
tuples_found = 0;
for (found = ISC_LIST_HEAD(zone_diff.tuples);
found != NULL;
found = ISC_LIST_NEXT(found, link))
{
tuples_found++;