mirror of
https://gitlab.isc.org/isc-projects/bind9
synced 2025-09-01 06:55:30 +00:00
3168. [bug] Nxdomain redirection could trigger a assert with
a ANY query. [RT #26017]
This commit is contained in:
3
CHANGES
3
CHANGES
@@ -1,3 +1,6 @@
|
||||
3168. [bug] Nxdomain redirection could trigger a assert with
|
||||
a ANY query. [RT #26017]
|
||||
|
||||
3167. [bug] Negative answers from forwarders were not being
|
||||
correctly tagged making them appear to not be cached.
|
||||
[RT #25380]
|
||||
|
@@ -15,7 +15,7 @@
|
||||
* PERFORMANCE OF THIS SOFTWARE.
|
||||
*/
|
||||
|
||||
/* $Id: query.c,v 1.371 2011/10/11 23:46:44 tbox Exp $ */
|
||||
/* $Id: query.c,v 1.372 2011/10/12 23:09:35 marka Exp $ */
|
||||
|
||||
/*! \file */
|
||||
|
||||
@@ -5005,7 +5005,8 @@ dns64_aaaaok(ns_client_t *client, dns_rdataset_t *rdataset,
|
||||
*/
|
||||
static isc_boolean_t
|
||||
redirect(ns_client_t *client, dns_name_t *name, dns_rdataset_t *rdataset,
|
||||
dns_dbnode_t **nodep, dns_db_t **dbp, dns_rdatatype_t qtype)
|
||||
dns_dbnode_t **nodep, dns_db_t **dbp, dns_dbversion_t **versionp,
|
||||
dns_rdatatype_t qtype)
|
||||
{
|
||||
dns_db_t *db = NULL;
|
||||
dns_dbnode_t *node = NULL;
|
||||
@@ -5016,6 +5017,7 @@ redirect(ns_client_t *client, dns_name_t *name, dns_rdataset_t *rdataset,
|
||||
dns_rdatatype_t type;
|
||||
dns_clientinfomethods_t cm;
|
||||
dns_clientinfo_t ci;
|
||||
ns_dbversion_t *dbversion;
|
||||
|
||||
CTRACE("redirect");
|
||||
|
||||
@@ -5064,11 +5066,17 @@ redirect(ns_client_t *client, dns_name_t *name, dns_rdataset_t *rdataset,
|
||||
if (result != ISC_R_SUCCESS)
|
||||
return (ISC_FALSE);
|
||||
|
||||
dbversion = query_findversion(client, db);
|
||||
if (dbversion == NULL) {
|
||||
dns_db_detach(&db);
|
||||
return (ISC_FALSE);
|
||||
}
|
||||
|
||||
/*
|
||||
* Lookup the requested data in the redirect zone.
|
||||
*/
|
||||
result = dns_db_findext(db, client->query.qname, NULL, qtype, 0,
|
||||
client->now, &node, found, &cm, &ci,
|
||||
result = dns_db_findext(db, client->query.qname, dbversion->version,
|
||||
qtype, 0, client->now, &node, found, &cm, &ci,
|
||||
&trdataset, NULL);
|
||||
if (result != ISC_R_SUCCESS) {
|
||||
if (dns_rdataset_isassociated(&trdataset))
|
||||
@@ -5094,6 +5102,7 @@ redirect(ns_client_t *client, dns_name_t *name, dns_rdataset_t *rdataset,
|
||||
dns_db_attach(db, dbp);
|
||||
dns_db_detachnode(db, &node);
|
||||
dns_db_detach(&db);
|
||||
*versionp = dbversion->version;
|
||||
|
||||
client->query.attributes |= (NS_QUERYATTR_NOAUTHORITY |
|
||||
NS_QUERYATTR_NOADDITIONAL);
|
||||
@@ -6020,7 +6029,8 @@ query_find(ns_client_t *client, dns_fetchevent_t *event, dns_rdatatype_t qtype)
|
||||
case DNS_R_NXDOMAIN:
|
||||
INSIST(is_zone);
|
||||
if (!empty_wild &&
|
||||
redirect(client, fname, rdataset, &node, &db, type))
|
||||
redirect(client, fname, rdataset, &node, &db, &version,
|
||||
type))
|
||||
break;
|
||||
if (dns_rdataset_isassociated(rdataset)) {
|
||||
/*
|
||||
@@ -6081,7 +6091,8 @@ query_find(ns_client_t *client, dns_fetchevent_t *event, dns_rdatatype_t qtype)
|
||||
goto cleanup;
|
||||
|
||||
case DNS_R_NCACHENXDOMAIN:
|
||||
if (redirect(client, fname, rdataset, &node, &db, type))
|
||||
if (redirect(client, fname, rdataset, &node, &db, &version,
|
||||
type))
|
||||
break;
|
||||
case DNS_R_NCACHENXRRSET:
|
||||
ncache_nxrrset:
|
||||
|
@@ -15,7 +15,7 @@
|
||||
* PERFORMANCE OF THIS SOFTWARE.
|
||||
*/
|
||||
|
||||
/* $Id: rbtdb.c,v 1.317 2011/10/11 00:09:03 each Exp $ */
|
||||
/* $Id: rbtdb.c,v 1.318 2011/10/12 23:09:35 marka Exp $ */
|
||||
|
||||
/*! \file */
|
||||
|
||||
@@ -365,9 +365,12 @@ typedef enum {
|
||||
dns_db_secure
|
||||
} dns_db_secure_t;
|
||||
|
||||
typedef struct dns_rbtdb dns_rbtdb_t;
|
||||
|
||||
typedef struct rbtdb_version {
|
||||
/* Not locked */
|
||||
rbtdb_serial_t serial;
|
||||
dns_rbtdb_t * rbtdb;
|
||||
/*
|
||||
* Protected in the refcount routines.
|
||||
* XXXJT: should we change the lock policy based on the refcount
|
||||
@@ -392,7 +395,7 @@ typedef struct rbtdb_version {
|
||||
|
||||
typedef ISC_LIST(rbtdb_version_t) rbtdb_versionlist_t;
|
||||
|
||||
typedef struct {
|
||||
struct dns_rbtdb {
|
||||
/* Unlocked. */
|
||||
dns_db_t common;
|
||||
/* Locks the data in this struct */
|
||||
@@ -452,7 +455,7 @@ typedef struct {
|
||||
|
||||
/* Unlocked */
|
||||
unsigned int quantum;
|
||||
} dns_rbtdb_t;
|
||||
};
|
||||
|
||||
#define RBTDB_ATTR_LOADED 0x01
|
||||
#define RBTDB_ATTR_LOADING 0x02
|
||||
@@ -1105,6 +1108,7 @@ newversion(dns_db_t *db, dns_dbversion_t **versionp) {
|
||||
version = allocate_version(rbtdb->common.mctx, rbtdb->next_serial, 1,
|
||||
ISC_TRUE);
|
||||
if (version != NULL) {
|
||||
version->rbtdb = rbtdb;
|
||||
version->commit_ok = ISC_TRUE;
|
||||
version->secure = rbtdb->current_version->secure;
|
||||
version->havensec3 = rbtdb->current_version->havensec3;
|
||||
@@ -1146,6 +1150,7 @@ attachversion(dns_db_t *db, dns_dbversion_t *source,
|
||||
unsigned int refs;
|
||||
|
||||
REQUIRE(VALID_RBTDB(rbtdb));
|
||||
INSIST(rbtversion != NULL && rbtversion->rbtdb == rbtdb);
|
||||
|
||||
isc_refcount_increment(&rbtversion->references, &refs);
|
||||
INSIST(refs > 1);
|
||||
@@ -2182,6 +2187,7 @@ closeversion(dns_db_t *db, dns_dbversion_t **versionp, isc_boolean_t commit) {
|
||||
|
||||
REQUIRE(VALID_RBTDB(rbtdb));
|
||||
version = (rbtdb_version_t *)*versionp;
|
||||
INSIST(version->rbtdb == rbtdb);
|
||||
|
||||
cleanup_version = NULL;
|
||||
ISC_LIST_INIT(cleanup_list);
|
||||
@@ -3649,6 +3655,8 @@ zone_find(dns_db_t *db, dns_name_t *name, dns_dbversion_t *version,
|
||||
search.rbtdb = (dns_rbtdb_t *)db;
|
||||
|
||||
REQUIRE(VALID_RBTDB(search.rbtdb));
|
||||
INSIST(version == NULL ||
|
||||
((rbtdb_version_t *)version)->rbtdb == (dns_rbtdb_t *)db);
|
||||
|
||||
/*
|
||||
* We don't care about 'now'.
|
||||
@@ -5544,6 +5552,7 @@ zone_findrdataset(dns_db_t *db, dns_dbnode_t *node, dns_dbversion_t *version,
|
||||
|
||||
REQUIRE(VALID_RBTDB(rbtdb));
|
||||
REQUIRE(type != dns_rdatatype_any);
|
||||
INSIST(rbtversion == NULL || rbtversion->rbtdb == rbtdb);
|
||||
|
||||
if (rbtversion == NULL) {
|
||||
currentversion(db, (dns_dbversion_t **) (void *)(&rbtversion));
|
||||
@@ -5732,6 +5741,8 @@ allrdatasets(dns_db_t *db, dns_dbnode_t *node, dns_dbversion_t *version,
|
||||
else {
|
||||
unsigned int refs;
|
||||
|
||||
INSIST(rbtversion->rbtdb == rbtdb);
|
||||
|
||||
isc_refcount_increment(&rbtversion->references,
|
||||
&refs);
|
||||
INSIST(refs > 1);
|
||||
@@ -6401,6 +6412,7 @@ addrdataset(dns_db_t *db, dns_dbnode_t *node, dns_dbversion_t *version,
|
||||
isc_boolean_t cache_is_overmem = ISC_FALSE;
|
||||
|
||||
REQUIRE(VALID_RBTDB(rbtdb));
|
||||
INSIST(rbtversion == NULL || rbtversion->rbtdb == rbtdb);
|
||||
|
||||
if (rbtdb->common.methods == &zone_methods)
|
||||
REQUIRE(((rbtnode->nsec == DNS_RBT_NSEC_NSEC3 &&
|
||||
@@ -6417,8 +6429,7 @@ addrdataset(dns_db_t *db, dns_dbnode_t *node, dns_dbversion_t *version,
|
||||
now = 0;
|
||||
|
||||
result = dns_rdataslab_fromrdataset(rdataset, rbtdb->common.mctx,
|
||||
®ion,
|
||||
sizeof(rdatasetheader_t));
|
||||
®ion, sizeof(rdatasetheader_t));
|
||||
if (result != ISC_R_SUCCESS)
|
||||
return (result);
|
||||
|
||||
@@ -6591,6 +6602,7 @@ subtractrdataset(dns_db_t *db, dns_dbnode_t *node, dns_dbversion_t *version,
|
||||
rbtdb_changed_t *changed;
|
||||
|
||||
REQUIRE(VALID_RBTDB(rbtdb));
|
||||
REQUIRE(rbtversion != NULL && rbtversion->rbtdb == rbtdb);
|
||||
|
||||
if (rbtdb->common.methods == &zone_methods)
|
||||
REQUIRE(((rbtnode->nsec == DNS_RBT_NSEC_NSEC3 &&
|
||||
@@ -6771,6 +6783,7 @@ deleterdataset(dns_db_t *db, dns_dbnode_t *node, dns_dbversion_t *version,
|
||||
rdatasetheader_t *newheader;
|
||||
|
||||
REQUIRE(VALID_RBTDB(rbtdb));
|
||||
INSIST(rbtversion == NULL || rbtversion->rbtdb == rbtdb);
|
||||
|
||||
if (type == dns_rdatatype_any)
|
||||
return (ISC_R_NOTIMPLEMENTED);
|
||||
@@ -7064,10 +7077,12 @@ static isc_result_t
|
||||
dump(dns_db_t *db, dns_dbversion_t *version, const char *filename,
|
||||
dns_masterformat_t masterformat) {
|
||||
dns_rbtdb_t *rbtdb;
|
||||
rbtdb_version_t *rbtversion = version;
|
||||
|
||||
rbtdb = (dns_rbtdb_t *)db;
|
||||
|
||||
REQUIRE(VALID_RBTDB(rbtdb));
|
||||
INSIST(rbtversion == NULL || rbtversion->rbtdb == rbtdb);
|
||||
|
||||
#ifdef BIND9
|
||||
return (dns_master_dump2(rbtdb->common.mctx, db, version,
|
||||
@@ -7206,6 +7221,7 @@ getnsec3parameters(dns_db_t *db, dns_dbversion_t *version, dns_hash_t *hash,
|
||||
rbtdb = (dns_rbtdb_t *)db;
|
||||
|
||||
REQUIRE(VALID_RBTDB(rbtdb));
|
||||
INSIST(rbtversion == NULL || rbtversion->rbtdb == rbtdb);
|
||||
|
||||
RWLOCK(&rbtdb->tree_lock, isc_rwlocktype_read);
|
||||
|
||||
@@ -7335,11 +7351,16 @@ resigned(dns_db_t *db, dns_rdataset_t *rdataset, dns_dbversion_t *version)
|
||||
|
||||
REQUIRE(VALID_RBTDB(rbtdb));
|
||||
REQUIRE(rdataset != NULL);
|
||||
REQUIRE(rdataset->methods == &rdataset_methods);
|
||||
REQUIRE(rbtdb->future_version == rbtversion);
|
||||
REQUIRE(rbtversion != NULL);
|
||||
REQUIRE(rbtversion->writer);
|
||||
REQUIRE(rbtversion->rbtdb == rbtdb);
|
||||
|
||||
node = rdataset->private2;
|
||||
INSIST(node != NULL);
|
||||
header = rdataset->private3;
|
||||
INSIST(header != NULL);
|
||||
header--;
|
||||
|
||||
RWLOCK(&rbtdb->tree_lock, isc_rwlocktype_write);
|
||||
@@ -7754,6 +7775,7 @@ dns_rbtdb_create
|
||||
free_rbtdb(rbtdb, ISC_FALSE, NULL);
|
||||
return (ISC_R_NOMEMORY);
|
||||
}
|
||||
rbtdb->current_version->rbtdb = rbtdb;
|
||||
rbtdb->current_version->secure = dns_db_insecure;
|
||||
rbtdb->current_version->havensec3 = ISC_FALSE;
|
||||
rbtdb->current_version->flags = 0;
|
||||
|
@@ -12,7 +12,7 @@
|
||||
# OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
|
||||
# PERFORMANCE OF THIS SOFTWARE.
|
||||
|
||||
# $Id: Makefile.in,v 1.8 2011/09/02 21:15:37 each Exp $
|
||||
# $Id: Makefile.in,v 1.9 2011/10/12 23:09:35 marka Exp $
|
||||
|
||||
srcdir = @srcdir@
|
||||
VPATH = @srcdir@
|
||||
@@ -42,7 +42,8 @@ SRCS = dnstest.c master_test.c dbiterator_test.c time_test.c \
|
||||
|
||||
SUBDIRS =
|
||||
TARGETS = master_test@EXEEXT@ dbiterator_test@EXEEXT@ time_test@EXEEXT@ \
|
||||
update_test@EXEEXT@ zonemgr_test@EXEEXT@ zt_test@EXEEXT@
|
||||
update_test@EXEEXT@ zonemgr_test@EXEEXT@ zt_test@EXEEXT@ \
|
||||
dbversion_test@EXEEXT@
|
||||
|
||||
@BIND9_MAKE_RULES@
|
||||
|
||||
@@ -71,6 +72,11 @@ dbiterator_test@EXEEXT@: dbiterator_test.@O@ dnstest.@O@ ${ISCDEPLIBS} ${DNSDEPL
|
||||
dbiterator_test.@O@ dnstest.@O@ ${DNSLIBS} \
|
||||
${ISCLIBS} ${LIBS}
|
||||
|
||||
dbversion_test@EXEEXT@: dbversion_test.@O@ dnstest.@O@ ${ISCDEPLIBS} ${DNSDEPLIBS}
|
||||
${LIBTOOL_MODE_LINK} ${PURIFY} ${CC} ${CFLAGS} ${LDFLAGS} -o $@ \
|
||||
dbversion_test.@O@ dnstest.@O@ ${DNSLIBS} \
|
||||
${ISCLIBS} ${LIBS}
|
||||
|
||||
zt_test@EXEEXT@: zt_test.@O@ dnstest.@O@ ${ISCDEPLIBS} ${DNSDEPLIBS}
|
||||
${LIBTOOL_MODE_LINK} ${PURIFY} ${CC} ${CFLAGS} ${LDFLAGS} -o $@ \
|
||||
zt_test.@O@ dnstest.@O@ ${DNSLIBS} \
|
||||
|
738
lib/dns/tests/dbversion_test.c
Normal file
738
lib/dns/tests/dbversion_test.c
Normal file
@@ -0,0 +1,738 @@
|
||||
/*
|
||||
* Copyright (C) 2011 Internet Systems Consortium, Inc. ("ISC")
|
||||
*
|
||||
* Permission to use, copy, modify, and/or distribute this software for any
|
||||
* purpose with or without fee is hereby granted, provided that the above
|
||||
* copyright notice and this permission notice appear in all copies.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
|
||||
* REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
|
||||
* AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
|
||||
* INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
|
||||
* LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
|
||||
* OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
|
||||
* PERFORMANCE OF THIS SOFTWARE.
|
||||
*/
|
||||
|
||||
/* $Id: dbversion_test.c,v 1.2 2011/10/12 23:09:35 marka Exp $ */
|
||||
|
||||
/*! \file */
|
||||
|
||||
#include <config.h>
|
||||
|
||||
#include <atf-c.h>
|
||||
|
||||
#include <unistd.h>
|
||||
#include <time.h>
|
||||
|
||||
#include <isc/file.h>
|
||||
#include <isc/result.h>
|
||||
#include <isc/serial.h>
|
||||
#include <isc/stdtime.h>
|
||||
#include <isc/msgcat.h>
|
||||
|
||||
#include <dns/db.h>
|
||||
#include <dns/rdatalist.h>
|
||||
#include <dns/rdataset.h>
|
||||
#include <dns/rdatasetiter.h>
|
||||
#include <dns/nsec3.h>
|
||||
|
||||
#include "dnstest.h"
|
||||
|
||||
static char tempname[11] = "dtXXXXXXXX";
|
||||
|
||||
static void
|
||||
callback(const char *file, int line, isc_assertiontype_t type,
|
||||
const char *cond)
|
||||
{
|
||||
UNUSED(file); UNUSED(line); UNUSED(type); UNUSED(cond);
|
||||
if (strcmp(tempname, "dtXXXXXXXX"))
|
||||
unlink(tempname);
|
||||
atf_tc_pass();
|
||||
exit(0);
|
||||
}
|
||||
|
||||
static dns_db_t *db1 = NULL, *db2 = NULL;
|
||||
static dns_dbversion_t *v1 = NULL, *v2 = NULL;
|
||||
|
||||
static void
|
||||
setup_db() {
|
||||
isc_result_t result;
|
||||
result = dns_db_create(mctx, "rbt", dns_rootname, dns_dbtype_zone,
|
||||
dns_rdataclass_in, 0, NULL, &db1);
|
||||
ATF_REQUIRE_EQ(result, ISC_R_SUCCESS);
|
||||
dns_db_newversion(db1, &v1);
|
||||
|
||||
result = dns_db_create(mctx, "rbt", dns_rootname, dns_dbtype_zone,
|
||||
dns_rdataclass_in, 0, NULL, &db2);
|
||||
ATF_REQUIRE_EQ(result, ISC_R_SUCCESS);
|
||||
dns_db_newversion(db2, &v2);
|
||||
}
|
||||
|
||||
static void
|
||||
close_db() {
|
||||
if (v1 != NULL) {
|
||||
dns_db_closeversion(db1, &v1, ISC_FALSE);
|
||||
ATF_REQUIRE_EQ(v1, NULL);
|
||||
}
|
||||
if (db1 != NULL) {
|
||||
dns_db_detach(&db1);
|
||||
ATF_REQUIRE_EQ(db1, NULL);
|
||||
}
|
||||
|
||||
if (v2 != NULL) {
|
||||
dns_db_closeversion(db2, &v2, ISC_FALSE);
|
||||
ATF_REQUIRE_EQ(v2, NULL);
|
||||
}
|
||||
if (db2 != NULL) {
|
||||
dns_db_detach(&db2);
|
||||
ATF_REQUIRE_EQ(db2, NULL);
|
||||
}
|
||||
}
|
||||
|
||||
#define VERSION(callback) ((callback == NULL) ? v1 : v2)
|
||||
#define VERSIONP(callback) ((callback == NULL) ? &v1 : &v2)
|
||||
/*
|
||||
* Individual unit tests
|
||||
*/
|
||||
static void
|
||||
attachversion(isc_assertioncallback_t callback) {
|
||||
isc_result_t result;
|
||||
dns_dbversion_t *v = NULL;
|
||||
|
||||
result = dns_test_begin(NULL, ISC_FALSE);
|
||||
ATF_REQUIRE_EQ(result, ISC_R_SUCCESS);
|
||||
|
||||
setup_db();
|
||||
|
||||
isc_assertion_setcallback(callback);
|
||||
dns_db_attachversion(db1, VERSION(callback), &v);
|
||||
if (callback != NULL)
|
||||
atf_tc_fail("dns_db_attachversion did not assert");
|
||||
|
||||
ATF_REQUIRE_EQ(v, v1);
|
||||
dns_db_closeversion(db1, &v, ISC_FALSE);
|
||||
ATF_REQUIRE_EQ(v, NULL);
|
||||
|
||||
close_db();
|
||||
dns_test_end();
|
||||
}
|
||||
|
||||
ATF_TC(attachversion);
|
||||
ATF_TC_HEAD(attachversion, tc) {
|
||||
atf_tc_set_md_var(tc, "descr", "check dns_db_attachversion passes with matching db/verison");
|
||||
}
|
||||
ATF_TC_BODY(attachversion, tc) {
|
||||
|
||||
UNUSED(tc);
|
||||
|
||||
attachversion(NULL);
|
||||
}
|
||||
|
||||
ATF_TC(attachversion_bad);
|
||||
ATF_TC_HEAD(attachversion_bad, tc) {
|
||||
atf_tc_set_md_var(tc, "descr", "check dns_db_attachversion aborts with mis-matching db/verison");
|
||||
}
|
||||
ATF_TC_BODY(attachversion_bad, tc) {
|
||||
|
||||
UNUSED(tc);
|
||||
|
||||
attachversion(callback);
|
||||
}
|
||||
|
||||
static void
|
||||
closeversion(isc_assertioncallback_t callback) {
|
||||
isc_result_t result;
|
||||
|
||||
result = dns_test_begin(NULL, ISC_FALSE);
|
||||
ATF_REQUIRE_EQ(result, ISC_R_SUCCESS);
|
||||
|
||||
setup_db();
|
||||
|
||||
isc_assertion_setcallback(callback);
|
||||
dns_db_closeversion(db1, VERSIONP(callback), ISC_FALSE);
|
||||
if (callback != NULL)
|
||||
atf_tc_fail("dns_db_closeversion did not assert");
|
||||
ATF_REQUIRE_EQ(v1, NULL);
|
||||
|
||||
close_db();
|
||||
dns_test_end();
|
||||
}
|
||||
|
||||
ATF_TC(closeversion);
|
||||
ATF_TC_HEAD(closeversion, tc) {
|
||||
atf_tc_set_md_var(tc, "descr", "check dns_db_closeversion passes with matching db/verison");
|
||||
}
|
||||
ATF_TC_BODY(closeversion, tc) {
|
||||
|
||||
UNUSED(tc);
|
||||
|
||||
closeversion(NULL);
|
||||
}
|
||||
|
||||
ATF_TC(closeversion_bad);
|
||||
ATF_TC_HEAD(closeversion_bad, tc) {
|
||||
atf_tc_set_md_var(tc, "descr", "check dns_db_closeversion asserts with mis-matching db/verison");
|
||||
}
|
||||
ATF_TC_BODY(closeversion_bad, tc) {
|
||||
|
||||
UNUSED(tc);
|
||||
|
||||
closeversion(callback);
|
||||
}
|
||||
|
||||
static void
|
||||
find(isc_assertioncallback_t callback) {
|
||||
isc_result_t result;
|
||||
dns_rdataset_t rdataset;
|
||||
dns_fixedname_t fixed;
|
||||
|
||||
result = dns_test_begin(NULL, ISC_FALSE);
|
||||
ATF_REQUIRE_EQ(result, ISC_R_SUCCESS);
|
||||
|
||||
setup_db();
|
||||
|
||||
dns_rdataset_init(&rdataset);
|
||||
dns_fixedname_init(&fixed);
|
||||
|
||||
isc_assertion_setcallback(callback);
|
||||
result = dns_db_find(db1, dns_rootname, VERSION(callback),
|
||||
dns_rdatatype_soa, 0, 0, NULL,
|
||||
dns_fixedname_name(&fixed), &rdataset, NULL);
|
||||
if (callback != NULL)
|
||||
atf_tc_fail("dns_db_find did not assert");
|
||||
ATF_REQUIRE_EQ(result, DNS_R_NXDOMAIN);
|
||||
|
||||
close_db();
|
||||
|
||||
dns_test_end();
|
||||
}
|
||||
ATF_TC(find);
|
||||
ATF_TC_HEAD(find, tc) {
|
||||
atf_tc_set_md_var(tc, "descr", "check dns_db_find passes with matching db/version");
|
||||
}
|
||||
ATF_TC_BODY(find, tc) {
|
||||
|
||||
UNUSED(tc);
|
||||
|
||||
find(NULL);
|
||||
}
|
||||
|
||||
ATF_TC(find_bad);
|
||||
ATF_TC_HEAD(find_bad, tc) {
|
||||
atf_tc_set_md_var(tc, "descr", "check dns_db_find asserts with mis-matching db/version");
|
||||
}
|
||||
ATF_TC_BODY(find_bad, tc) {
|
||||
|
||||
UNUSED(tc);
|
||||
|
||||
find(callback);
|
||||
}
|
||||
|
||||
static void
|
||||
allrdatasets(isc_assertioncallback_t callback) {
|
||||
isc_result_t result;
|
||||
dns_dbnode_t *node = NULL;
|
||||
dns_rdatasetiter_t *iterator = NULL;
|
||||
|
||||
result = dns_test_begin(NULL, ISC_FALSE);
|
||||
ATF_REQUIRE_EQ(result, ISC_R_SUCCESS);
|
||||
|
||||
setup_db();
|
||||
|
||||
result = dns_db_findnode(db1, dns_rootname, ISC_FALSE, &node);
|
||||
ATF_REQUIRE_EQ(result, ISC_R_SUCCESS);
|
||||
|
||||
isc_assertion_setcallback(callback);
|
||||
result = dns_db_allrdatasets(db1, node, VERSION(callback), 0,
|
||||
&iterator);
|
||||
if (callback != NULL)
|
||||
atf_tc_fail("dns_db_allrdatasets did not assert");
|
||||
ATF_REQUIRE_EQ(result, ISC_R_SUCCESS);
|
||||
|
||||
dns_rdatasetiter_destroy(&iterator);
|
||||
ATF_REQUIRE_EQ(iterator, NULL);
|
||||
|
||||
dns_db_detachnode(db1, &node);
|
||||
ATF_REQUIRE_EQ(node, NULL);
|
||||
|
||||
close_db();
|
||||
|
||||
dns_test_end();
|
||||
}
|
||||
|
||||
ATF_TC(allrdatasets);
|
||||
ATF_TC_HEAD(allrdatasets, tc) {
|
||||
atf_tc_set_md_var(tc, "descr", "check dns_db_allrdatasets passes with matching db/version");
|
||||
}
|
||||
ATF_TC_BODY(allrdatasets, tc) {
|
||||
|
||||
UNUSED(tc);
|
||||
|
||||
allrdatasets(NULL);
|
||||
}
|
||||
|
||||
ATF_TC(allrdatasets_bad);
|
||||
ATF_TC_HEAD(allrdatasets_bad, tc) {
|
||||
atf_tc_set_md_var(tc, "descr", "check dns_db_allrdatasets aborts with mis-matching db/version");
|
||||
}
|
||||
ATF_TC_BODY(allrdatasets_bad, tc) {
|
||||
|
||||
UNUSED(tc);
|
||||
|
||||
allrdatasets(callback);
|
||||
}
|
||||
|
||||
static void
|
||||
findrdataset(isc_assertioncallback_t callback) {
|
||||
isc_result_t result;
|
||||
dns_rdataset_t rdataset;
|
||||
dns_fixedname_t fixed;
|
||||
dns_dbnode_t *node = NULL;
|
||||
|
||||
result = dns_test_begin(NULL, ISC_FALSE);
|
||||
ATF_REQUIRE_EQ(result, ISC_R_SUCCESS);
|
||||
|
||||
setup_db();
|
||||
|
||||
dns_rdataset_init(&rdataset);
|
||||
dns_fixedname_init(&fixed);
|
||||
|
||||
result = dns_db_findnode(db1, dns_rootname, ISC_FALSE, &node);
|
||||
ATF_REQUIRE_EQ(result, ISC_R_SUCCESS);
|
||||
|
||||
isc_assertion_setcallback(callback);
|
||||
result = dns_db_findrdataset(db1, node, VERSION(callback),
|
||||
dns_rdatatype_soa, 0, 0, &rdataset, NULL);
|
||||
if (callback != NULL)
|
||||
atf_tc_fail("dns_db_findrdataset did not assert");
|
||||
ATF_REQUIRE_EQ(result, ISC_R_NOTFOUND);
|
||||
|
||||
dns_db_detachnode(db1, &node);
|
||||
ATF_REQUIRE_EQ(node, NULL);
|
||||
|
||||
close_db();
|
||||
|
||||
dns_test_end();
|
||||
}
|
||||
|
||||
ATF_TC(findrdataset);
|
||||
ATF_TC_HEAD(findrdataset, tc) {
|
||||
atf_tc_set_md_var(tc, "descr", "check dns_db_findrdataset passes with matching db/version");
|
||||
}
|
||||
ATF_TC_BODY(findrdataset, tc) {
|
||||
|
||||
UNUSED(tc);
|
||||
|
||||
findrdataset(NULL);
|
||||
}
|
||||
|
||||
ATF_TC(findrdataset_bad);
|
||||
ATF_TC_HEAD(findrdataset_bad, tc) {
|
||||
atf_tc_set_md_var(tc, "descr", "check dns_db_findrdataset aborts with mis-matching db/version");
|
||||
}
|
||||
ATF_TC_BODY(findrdataset_bad, tc) {
|
||||
|
||||
UNUSED(tc);
|
||||
|
||||
findrdataset(callback);
|
||||
}
|
||||
|
||||
static void
|
||||
deleterdataset(isc_assertioncallback_t callback) {
|
||||
isc_result_t result;
|
||||
dns_rdataset_t rdataset;
|
||||
dns_fixedname_t fixed;
|
||||
dns_dbnode_t *node = NULL;
|
||||
|
||||
result = dns_test_begin(NULL, ISC_FALSE);
|
||||
ATF_REQUIRE_EQ(result, ISC_R_SUCCESS);
|
||||
|
||||
setup_db();
|
||||
|
||||
dns_rdataset_init(&rdataset);
|
||||
dns_fixedname_init(&fixed);
|
||||
|
||||
result = dns_db_findnode(db1, dns_rootname, ISC_FALSE, &node);
|
||||
ATF_REQUIRE_EQ(result, ISC_R_SUCCESS);
|
||||
|
||||
isc_assertion_setcallback(callback);
|
||||
result = dns_db_deleterdataset(db1, node, VERSION(callback),
|
||||
dns_rdatatype_soa, 0);
|
||||
if (callback != NULL)
|
||||
atf_tc_fail("dns_db_deleterdataset did not assert");
|
||||
ATF_REQUIRE_EQ(result, DNS_R_UNCHANGED);
|
||||
|
||||
dns_db_detachnode(db1, &node);
|
||||
ATF_REQUIRE_EQ(node, NULL);
|
||||
|
||||
close_db();
|
||||
|
||||
dns_test_end();
|
||||
}
|
||||
|
||||
ATF_TC(deleterdataset);
|
||||
ATF_TC_HEAD(deleterdataset, tc) {
|
||||
atf_tc_set_md_var(tc, "descr", "check dns_db_deleterdataset passes with matching db/version");
|
||||
}
|
||||
ATF_TC_BODY(deleterdataset, tc) {
|
||||
|
||||
UNUSED(tc);
|
||||
|
||||
deleterdataset(NULL);
|
||||
}
|
||||
|
||||
ATF_TC(deleterdataset_bad);
|
||||
ATF_TC_HEAD(deleterdataset_bad, tc) {
|
||||
atf_tc_set_md_var(tc, "descr", "check dns_db_deleterdataset aborts with mis-matching db/version");
|
||||
}
|
||||
ATF_TC_BODY(deleterdataset_bad, tc) {
|
||||
|
||||
UNUSED(tc);
|
||||
|
||||
deleterdataset(callback);
|
||||
}
|
||||
|
||||
static void
|
||||
subtract(isc_assertioncallback_t callback) {
|
||||
isc_result_t result;
|
||||
dns_rdataset_t rdataset;
|
||||
dns_fixedname_t fixed;
|
||||
dns_dbnode_t *node = NULL;
|
||||
dns_rdatalist_t rdatalist;
|
||||
|
||||
result = dns_test_begin(NULL, ISC_FALSE);
|
||||
ATF_REQUIRE_EQ(result, ISC_R_SUCCESS);
|
||||
|
||||
setup_db();
|
||||
|
||||
dns_rdataset_init(&rdataset);
|
||||
dns_rdatalist_init(&rdatalist);
|
||||
dns_fixedname_init(&fixed);
|
||||
|
||||
rdatalist.rdclass = dns_rdataclass_in;
|
||||
|
||||
result = dns_rdatalist_tordataset(&rdatalist, &rdataset);
|
||||
ATF_REQUIRE_EQ(result, ISC_R_SUCCESS);
|
||||
|
||||
result = dns_db_findnode(db1, dns_rootname, ISC_FALSE, &node);
|
||||
ATF_REQUIRE_EQ(result, ISC_R_SUCCESS);
|
||||
|
||||
isc_assertion_setcallback(callback);
|
||||
result = dns_db_subtractrdataset(db1, node, VERSION(callback),
|
||||
&rdataset, 0, NULL);
|
||||
if (callback != NULL)
|
||||
atf_tc_fail("dns_db_dns_db_subtractrdataset did not assert");
|
||||
ATF_REQUIRE_EQ(result, DNS_R_UNCHANGED);
|
||||
|
||||
dns_db_detachnode(db1, &node);
|
||||
ATF_REQUIRE_EQ(node, NULL);
|
||||
|
||||
close_db();
|
||||
|
||||
dns_test_end();
|
||||
}
|
||||
|
||||
ATF_TC(subtractrdataset);
|
||||
ATF_TC_HEAD(subtractrdataset, tc) {
|
||||
atf_tc_set_md_var(tc, "descr", "check dns_db_subtractrdataset passes with matching db/version");
|
||||
}
|
||||
ATF_TC_BODY(subtractrdataset, tc) {
|
||||
|
||||
UNUSED(tc);
|
||||
|
||||
subtract(NULL);
|
||||
}
|
||||
|
||||
ATF_TC(subtractrdataset_bad);
|
||||
ATF_TC_HEAD(subtractrdataset_bad, tc) {
|
||||
atf_tc_set_md_var(tc, "descr", "check dns_db_subtractrdataset aborts with mis-matching db/version");
|
||||
}
|
||||
ATF_TC_BODY(subtractrdataset_bad, tc) {
|
||||
|
||||
UNUSED(tc);
|
||||
|
||||
subtract(callback);
|
||||
}
|
||||
|
||||
static void
|
||||
dump(isc_assertioncallback_t callback) {
|
||||
isc_result_t result;
|
||||
FILE *f = NULL;
|
||||
|
||||
result = dns_test_begin(NULL, ISC_FALSE);
|
||||
ATF_REQUIRE_EQ(result, ISC_R_SUCCESS);
|
||||
|
||||
setup_db();
|
||||
|
||||
result = isc_file_openunique(tempname, &f);
|
||||
fclose(f);
|
||||
ATF_REQUIRE_EQ(result, ISC_R_SUCCESS);
|
||||
|
||||
isc_assertion_setcallback(callback);
|
||||
result = dns_db_dump(db1, VERSION(callback), tempname);
|
||||
(void)unlink(tempname);
|
||||
if (callback != NULL)
|
||||
atf_tc_fail("dns_db_dump did not assert");
|
||||
ATF_REQUIRE_EQ(result, ISC_R_SUCCESS);
|
||||
|
||||
close_db();
|
||||
|
||||
dns_test_end();
|
||||
}
|
||||
|
||||
ATF_TC(dump);
|
||||
ATF_TC_HEAD(dump, tc) {
|
||||
atf_tc_set_md_var(tc, "descr", "check dns_db_dump passes with matching db/version");
|
||||
}
|
||||
ATF_TC_BODY(dump, tc) {
|
||||
|
||||
UNUSED(tc);
|
||||
|
||||
dump(NULL);
|
||||
}
|
||||
|
||||
ATF_TC(dump_bad);
|
||||
ATF_TC_HEAD(dump_bad, tc) {
|
||||
atf_tc_set_md_var(tc, "descr", "check dns_db_dump aborts with mis-matching db/version");
|
||||
}
|
||||
ATF_TC_BODY(dump_bad, tc) {
|
||||
|
||||
UNUSED(tc);
|
||||
|
||||
dump(callback);
|
||||
}
|
||||
|
||||
static void
|
||||
addrdataset(isc_assertioncallback_t callback) {
|
||||
isc_result_t result;
|
||||
dns_rdataset_t rdataset;
|
||||
dns_fixedname_t fixed;
|
||||
dns_dbnode_t *node = NULL;
|
||||
dns_rdatalist_t rdatalist;
|
||||
|
||||
result = dns_test_begin(NULL, ISC_FALSE);
|
||||
ATF_REQUIRE_EQ(result, ISC_R_SUCCESS);
|
||||
|
||||
setup_db();
|
||||
|
||||
dns_rdataset_init(&rdataset);
|
||||
dns_rdatalist_init(&rdatalist);
|
||||
dns_fixedname_init(&fixed);
|
||||
|
||||
rdatalist.rdclass = dns_rdataclass_in;
|
||||
|
||||
result = dns_rdatalist_tordataset(&rdatalist, &rdataset);
|
||||
ATF_REQUIRE_EQ(result, ISC_R_SUCCESS);
|
||||
|
||||
result = dns_db_findnode(db1, dns_rootname, ISC_FALSE, &node);
|
||||
ATF_REQUIRE_EQ(result, ISC_R_SUCCESS);
|
||||
|
||||
isc_assertion_setcallback(callback);
|
||||
result = dns_db_addrdataset(db1, node, VERSION(callback), 0, &rdataset,
|
||||
0, NULL);
|
||||
if (callback != NULL)
|
||||
atf_tc_fail("dns_db_adddataset did not assert");
|
||||
ATF_REQUIRE_EQ(result, ISC_R_SUCCESS);
|
||||
|
||||
dns_db_detachnode(db1, &node);
|
||||
ATF_REQUIRE_EQ(node, NULL);
|
||||
|
||||
close_db();
|
||||
|
||||
dns_test_end();
|
||||
}
|
||||
|
||||
ATF_TC(addrdataset);
|
||||
ATF_TC_HEAD(addrdataset, tc) {
|
||||
atf_tc_set_md_var(tc, "descr", "check dns_db_addrdataset passes with matching db/version");
|
||||
}
|
||||
ATF_TC_BODY(addrdataset, tc) {
|
||||
|
||||
UNUSED(tc);
|
||||
|
||||
addrdataset(NULL);
|
||||
}
|
||||
|
||||
ATF_TC(addrdataset_bad);
|
||||
ATF_TC_HEAD(addrdataset_bad, tc) {
|
||||
atf_tc_set_md_var(tc, "descr", "check dns_db_addrdataset aborts with mis-matching db/version");
|
||||
}
|
||||
ATF_TC_BODY(addrdataset_bad, tc) {
|
||||
|
||||
UNUSED(tc);
|
||||
|
||||
addrdataset(callback);
|
||||
}
|
||||
|
||||
static void
|
||||
getnsec3parameters(isc_assertioncallback_t callback) {
|
||||
isc_result_t result;
|
||||
dns_hash_t hash;
|
||||
isc_uint8_t flags;
|
||||
isc_uint16_t iterations;
|
||||
unsigned char salt[DNS_NSEC3_SALTSIZE];
|
||||
size_t salt_length = sizeof(salt);
|
||||
|
||||
result = dns_test_begin(NULL, ISC_FALSE);
|
||||
ATF_REQUIRE_EQ(result, ISC_R_SUCCESS);
|
||||
|
||||
setup_db();
|
||||
|
||||
isc_assertion_setcallback(callback);
|
||||
result = dns_db_getnsec3parameters(db1, VERSION(callback), &hash,
|
||||
&flags, &iterations, salt,
|
||||
&salt_length);
|
||||
if (callback != NULL)
|
||||
atf_tc_fail("dns_db_dump did not assert");
|
||||
ATF_REQUIRE_EQ(result, ISC_R_NOTFOUND);
|
||||
|
||||
close_db();
|
||||
|
||||
dns_test_end();
|
||||
}
|
||||
|
||||
ATF_TC(getnsec3parameters);
|
||||
ATF_TC_HEAD(getnsec3parameters, tc) {
|
||||
atf_tc_set_md_var(tc, "descr", "check dns_db_getnsec3parameters passes with matching db/version");
|
||||
}
|
||||
ATF_TC_BODY(getnsec3parameters, tc) {
|
||||
|
||||
UNUSED(tc);
|
||||
|
||||
getnsec3parameters(NULL);
|
||||
}
|
||||
|
||||
ATF_TC(getnsec3parameters_bad);
|
||||
ATF_TC_HEAD(getnsec3parameters_bad, tc) {
|
||||
atf_tc_set_md_var(tc, "descr", "check dns_db_getnsec3parameters aborts with mis-matching db/version");
|
||||
}
|
||||
ATF_TC_BODY(getnsec3parameters_bad, tc) {
|
||||
|
||||
UNUSED(tc);
|
||||
|
||||
getnsec3parameters(callback);
|
||||
}
|
||||
|
||||
static void
|
||||
resigned(isc_assertioncallback_t callback) {
|
||||
isc_result_t result;
|
||||
dns_rdataset_t rdataset, added;
|
||||
dns_dbnode_t *node = NULL;
|
||||
dns_rdatalist_t rdatalist;
|
||||
dns_rdata_rrsig_t rrsig;
|
||||
dns_rdata_t rdata = DNS_RDATA_INIT;
|
||||
isc_buffer_t b;
|
||||
unsigned char buf[1024];
|
||||
|
||||
result = dns_test_begin(NULL, ISC_FALSE);
|
||||
ATF_REQUIRE_EQ(result, ISC_R_SUCCESS);
|
||||
|
||||
setup_db();
|
||||
|
||||
/*
|
||||
* Create a dummy RRSIG record and set a resigning time.
|
||||
*/
|
||||
dns_rdataset_init(&added);
|
||||
dns_rdataset_init(&rdataset);
|
||||
dns_rdatalist_init(&rdatalist);
|
||||
isc_buffer_init(&b, buf, sizeof(buf));
|
||||
|
||||
DNS_RDATACOMMON_INIT(&rrsig, dns_rdatatype_rrsig, dns_rdataclass_in);
|
||||
rrsig.covered = dns_rdatatype_a;
|
||||
rrsig.algorithm = 100;
|
||||
rrsig.labels = 0;
|
||||
rrsig.originalttl = 0;
|
||||
rrsig.timeexpire = 3600;
|
||||
rrsig.timesigned = 0;
|
||||
rrsig.keyid = 0;
|
||||
dns_name_init(&rrsig.signer, NULL);
|
||||
dns_name_clone(dns_rootname, &rrsig.signer);
|
||||
rrsig.siglen = 0;
|
||||
rrsig.signature = NULL;
|
||||
|
||||
result = dns_rdata_fromstruct(&rdata, dns_rdataclass_in,
|
||||
dns_rdatatype_rrsig, &rrsig, &b);
|
||||
|
||||
rdatalist.rdclass = dns_rdataclass_in;
|
||||
rdatalist.type = dns_rdatatype_rrsig;
|
||||
ISC_LIST_APPEND(rdatalist.rdata, &rdata, link);
|
||||
|
||||
result = dns_rdatalist_tordataset(&rdatalist, &rdataset);
|
||||
ATF_REQUIRE_EQ(result, ISC_R_SUCCESS);
|
||||
|
||||
rdataset.attributes |= DNS_RDATASETATTR_RESIGN;
|
||||
rdataset.resign = 7200;
|
||||
|
||||
result = dns_db_findnode(db1, dns_rootname, ISC_FALSE, &node);
|
||||
ATF_REQUIRE_EQ(result, ISC_R_SUCCESS);
|
||||
|
||||
result = dns_db_addrdataset(db1, node, v1, 0, &rdataset, 0, &added);
|
||||
ATF_REQUIRE_EQ(result, ISC_R_SUCCESS);
|
||||
|
||||
dns_db_detachnode(db1, &node);
|
||||
ATF_REQUIRE_EQ(node, NULL);
|
||||
|
||||
isc_assertion_setcallback(callback);
|
||||
dns_db_resigned(db1, &added, VERSION(callback));
|
||||
if (callback != NULL)
|
||||
atf_tc_fail("dns_db_resigned did not assert");
|
||||
|
||||
dns_rdataset_disassociate(&added);
|
||||
|
||||
close_db();
|
||||
|
||||
dns_test_end();
|
||||
}
|
||||
|
||||
ATF_TC(resigned);
|
||||
ATF_TC_HEAD(resigned, tc) {
|
||||
atf_tc_set_md_var(tc, "descr", "check dns_rdataset_resigned passes with matching db/version");
|
||||
}
|
||||
ATF_TC_BODY(resigned, tc) {
|
||||
|
||||
UNUSED(tc);
|
||||
|
||||
resigned(NULL);
|
||||
}
|
||||
|
||||
ATF_TC(resigned_bad);
|
||||
ATF_TC_HEAD(resigned_bad, tc) {
|
||||
atf_tc_set_md_var(tc, "descr", "check dns_rdataset_resigned aborts with mis-matching db/version");
|
||||
}
|
||||
ATF_TC_BODY(resigned_bad, tc) {
|
||||
|
||||
UNUSED(tc);
|
||||
|
||||
resigned(callback);
|
||||
}
|
||||
|
||||
/*
|
||||
* Main
|
||||
*/
|
||||
ATF_TP_ADD_TCS(tp) {
|
||||
ATF_TP_ADD_TC(tp, dump);
|
||||
ATF_TP_ADD_TC(tp, dump_bad);
|
||||
ATF_TP_ADD_TC(tp, find);
|
||||
ATF_TP_ADD_TC(tp, find_bad);
|
||||
ATF_TP_ADD_TC(tp, allrdatasets);
|
||||
ATF_TP_ADD_TC(tp, allrdatasets_bad);
|
||||
ATF_TP_ADD_TC(tp, findrdataset);
|
||||
ATF_TP_ADD_TC(tp, findrdataset_bad);
|
||||
ATF_TP_ADD_TC(tp, addrdataset);
|
||||
ATF_TP_ADD_TC(tp, addrdataset_bad);
|
||||
ATF_TP_ADD_TC(tp, deleterdataset);
|
||||
ATF_TP_ADD_TC(tp, deleterdataset_bad);
|
||||
ATF_TP_ADD_TC(tp, subtractrdataset);
|
||||
ATF_TP_ADD_TC(tp, subtractrdataset_bad);
|
||||
ATF_TP_ADD_TC(tp, attachversion);
|
||||
ATF_TP_ADD_TC(tp, attachversion_bad);
|
||||
ATF_TP_ADD_TC(tp, closeversion);
|
||||
ATF_TP_ADD_TC(tp, closeversion_bad);
|
||||
ATF_TP_ADD_TC(tp, getnsec3parameters);
|
||||
ATF_TP_ADD_TC(tp, getnsec3parameters_bad);
|
||||
ATF_TP_ADD_TC(tp, resigned);
|
||||
ATF_TP_ADD_TC(tp, resigned_bad);
|
||||
|
||||
return (atf_no_error());
|
||||
}
|
@@ -14,9 +14,7 @@
|
||||
* PERFORMANCE OF THIS SOFTWARE.
|
||||
*/
|
||||
|
||||
/* $Id: update_test.c,v 1.5 2011/08/23 01:29:38 each Exp $ */
|
||||
|
||||
/* $Id: */
|
||||
/* $Id: update_test.c,v 1.6 2011/10/12 23:09:35 marka Exp $ */
|
||||
|
||||
/*! \file */
|
||||
|
||||
|
Reference in New Issue
Block a user