clear AD flag when altering response messages

- the AD flag was not being cleared correctly when filtering
- enabled dnssec valdiation in the filter-aaaa test to confirm this
  works correctly now
This commit is contained in:
Evan Hunt 2018-09-14 12:32:36 -07:00
parent 055bf2665c
commit 427e9ca357
23 changed files with 340 additions and 267 deletions

View file

@ -11,16 +11,6 @@ srcdir = @srcdir@
VPATH = @srcdir@
top_srcdir = @top_srcdir@
VERSION=@BIND9_VERSION@
@BIND9_PRODUCT@
@BIND9_DESCRIPTION@
@BIND9_SRCID@
@BIND9_CONFIGARGS@
@BIND9_MAKE_INCLUDES@
CINCLUDES = -I${srcdir}/include -I${srcdir}/unix/include -I. \
@ -40,8 +30,6 @@ TARGETS = @SO_TARGETS@
SO_OBJS = filter-aaaa.@O@
SO_SRCS = filter-aaaa.c
OBJS =
CFLAGS = @CFLAGS@ @SO_CFLAGS@
SO_LDFLAGS = @LDFLAGS@ @SO_LDFLAGS@

View file

@ -13,29 +13,45 @@
#include <config.h>
#include <inttypes.h>
#include <stdbool.h>
#include <string.h>
#include <isc/buffer.h>
#include <isc/hash.h>
#include <isc/lib.h>
#include <isc/log.h>
#include <isc/mem.h>
#include <isc/netaddr.h>
#include <isc/result.h>
#include <isc/types.h>
#include <isc/util.h>
#include <isccfg/aclconf.h>
#include <isccfg/cfg.h>
#include <isccfg/grammar.h>
#include <isccfg/namedconf.h>
#include <dns/acl.h>
#include <dns/result.h>
#include <ns/client.h>
#include <ns/hooks.h>
#include <ns/log.h>
#include <ns/query.h>
#include <ns/types.h>
#define CHECK(r) \
do { \
result = (r); \
if (result != ISC_R_SUCCESS) \
goto cleanup; \
#include <dns/acl.h>
#include <dns/db.h>
#include <dns/enumtype.h>
#include <dns/log.h>
#include <dns/message.h>
#include <dns/rdataset.h>
#include <dns/result.h>
#include <dns/types.h>
#define CHECK(op) \
do { \
result = (op); \
if (result != ISC_R_SUCCESS) { \
goto cleanup; \
} \
} while (0)
/*
@ -228,23 +244,20 @@ parse_parameters(const char *parameters, const void *cfg,
}
/**
** Mandatory hook API functions.
** Mandatory hook API functions:
**
** - hook_destroy
** - hook_register
** - hook_version
**/
/*
* Prototypes for the hook module API functions defined below.
*/
ns_hook_destroy_t hook_destroy;
ns_hook_register_t hook_register;
ns_hook_version_t hook_version;
/*
* Called by ns_hookmodule_load() to register hook functions into
* a hook table.
*/
isc_result_t
hook_register(const unsigned int modid, const char *parameters,
const char *file, unsigned long line,
const char *cfg_file, unsigned long cfg_line,
const void *cfg, void *actx,
ns_hookctx_t *hctx, ns_hooktable_t *hooktable, void **instp)
{
@ -254,20 +267,14 @@ hook_register(const unsigned int modid, const char *parameters,
module_id = modid;
if (parameters != NULL) {
isc_log_write(hctx->lctx, NS_LOGCATEGORY_GENERAL,
NS_LOGMODULE_HOOKS, ISC_LOG_INFO,
"loading params for 'filter-aaaa' "
"module from %s:%lu",
file, line);
isc_log_write(hctx->lctx, NS_LOGCATEGORY_GENERAL,
NS_LOGMODULE_HOOKS, ISC_LOG_INFO,
"loading 'filter-aaaa' "
"module from %s:%lu, %s parameters",
cfg_file, cfg_line, parameters != NULL ? "with" : "no");
if (parameters != NULL) {
CHECK(parse_parameters(parameters, cfg, actx, hctx));
} else {
isc_log_write(hctx->lctx, NS_LOGCATEGORY_GENERAL,
NS_LOGMODULE_HOOKS, ISC_LOG_INFO,
"loading 'filter-aaaa' "
"module from %s:%lu, no parameters",
file, line);
}
ns_hook_add(hooktable, NS_QUERY_QCTX_INITIALIZED, &filter_init);
@ -304,7 +311,7 @@ hook_register(const unsigned int modid, const char *parameters,
}
/*
* Called by ns_hookmodule_cleanup(); frees memory allocated by
* Called by ns_hookmodule_unload_all(); frees memory allocated by
* the module when it was registered.
*/
void
@ -325,18 +332,16 @@ hook_destroy(void **instp) {
* Returns hook module API version for compatibility checks.
*/
int
hook_version(unsigned int *flags) {
UNUSED(flags);
hook_version(void) {
return (NS_HOOK_VERSION);
}
/**
** "filter-aaaa" feature implementation begins here
** "filter-aaaa" feature implementation begins here.
**/
/*
* Check whether this is a V4 client.
* Check whether this is an IPv4 client.
*/
static bool
is_v4_client(ns_client_t *client) {
@ -352,7 +357,7 @@ is_v4_client(ns_client_t *client) {
}
/*
* Check whether this is a V6 client.
* Check whether this is an IPv6 client.
*/
static bool
is_v6_client(ns_client_t *client) {
@ -389,7 +394,7 @@ filter_qctx_initialize(void *hookdata, void *cbdata, isc_result_t *resp) {
}
/*
* Determine whether this client should have AAAA filtered nor not,
* Determine whether this client should have AAAA filtered or not,
* based on the client address family and the settings of
* filter-aaaa-on-v4 and filter-aaaa-on-v6.
*/
@ -474,6 +479,7 @@ filter_respond_begin(void *hookdata, void *cbdata, isc_result_t *resp) {
* cached an A if it existed.
*/
if (result == ISC_R_SUCCESS) {
qctx->client->message->flags &= ~DNS_MESSAGEFLAG_AD;
qctx->rdataset->attributes |= DNS_RDATASETATTR_RENDERED;
if (qctx->sigrdataset != NULL &&
dns_rdataset_isassociated(qctx->sigrdataset))
@ -511,7 +517,6 @@ filter_respond_begin(void *hookdata, void *cbdata, isc_result_t *resp) {
((qctx->client->hookflags[module_id] &
FILTER_AAAA_RECURSING) != 0))
{
dns_rdataset_t *mrdataset = NULL;
dns_rdataset_t *sigrdataset = NULL;
@ -520,6 +525,7 @@ filter_respond_begin(void *hookdata, void *cbdata, isc_result_t *resp) {
dns_rdatatype_aaaa, 0,
NULL, &mrdataset);
if (result == ISC_R_SUCCESS) {
qctx->client->message->flags &= ~DNS_MESSAGEFLAG_AD;
mrdataset->attributes |= DNS_RDATASETATTR_RENDERED;
}
@ -529,6 +535,7 @@ filter_respond_begin(void *hookdata, void *cbdata, isc_result_t *resp) {
dns_rdatatype_aaaa,
NULL, &sigrdataset);
if (result == ISC_R_SUCCESS) {
qctx->client->message->flags &= ~DNS_MESSAGEFLAG_AD;
sigrdataset->attributes |= DNS_RDATASETATTR_RENDERED;
}
@ -593,6 +600,7 @@ filter_respond_any_found(void *hookdata, void *cbdata, isc_result_t *resp) {
(aaaa_sig == NULL || !WANTDNSSEC(qctx->client) ||
**mode == BREAK_DNSSEC))
{
qctx->client->message->flags &= ~DNS_MESSAGEFLAG_AD;
aaaa->attributes |= DNS_RDATASETATTR_RENDERED;
if (aaaa_sig != NULL) {
aaaa_sig->attributes |= DNS_RDATASETATTR_RENDERED;
@ -605,7 +613,7 @@ filter_respond_any_found(void *hookdata, void *cbdata, isc_result_t *resp) {
/*
* Hide AAAA rrsets in the additional section if there is a matching A,
* and hide NS in the additional section if AAAA was filtered in the answer
* and hide NS in the authority section if AAAA was filtered in the answer
* section.
*/
static bool
@ -674,6 +682,8 @@ filter_query_done_send(void *hookdata, void *cbdata, isc_result_t *resp) {
result = dns_message_findtype(name, dns_rdatatype_ns,
0, &ns);
if (result == ISC_R_SUCCESS) {
qctx->client->message->flags &=
~DNS_MESSAGEFLAG_AD;
ns->attributes |= DNS_RDATASETATTR_RENDERED;
}

View file

@ -50,7 +50,7 @@
to omit some IPv6 addresses when responding to clients.
</para>
<para>
Until BIND 9.12, this feature was impleented natively in
Until BIND 9.12, this feature was implemented natively in
<command>named</command> and enabled with the
<command>filter-aaaa</command> ACL and the
<command>filter-aaaa-on-v4</command> and

View file

@ -1544,6 +1544,7 @@ configure_hook(ns_hooktable_t *hooktable, const unsigned int modid,
isc_result_t result = ISC_R_SUCCESS;
const cfg_obj_t *obj;
const char *type, *library;
const char *parameters = NULL;
/* Get the path to the hook module. */
obj = cfg_tuple_get(hook, "type");
@ -1560,22 +1561,12 @@ configure_hook(ns_hooktable_t *hooktable, const unsigned int modid,
obj = cfg_tuple_get(hook, "parameters");
if (obj != NULL && cfg_obj_isstring(obj)) {
result = ns_hookmodule_load(library, modid,
cfg_obj_asstring(obj),
cfg_obj_file(obj),
cfg_obj_line(obj),
config,
named_g_aclconfctx,
hctx, hooktable);
} else {
result = ns_hookmodule_load(library, modid, NULL,
cfg_obj_file(hook),
cfg_obj_line(hook),
config,
named_g_aclconfctx,
hctx, hooktable);
parameters = cfg_obj_asstring(obj);
}
result = ns_hookmodule_load(library, modid, parameters,
cfg_obj_file(obj), cfg_obj_line(obj),
config, named_g_aclconfctx,
hctx, hooktable);
if (result != ISC_R_SUCCESS) {
isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
NAMED_LOGMODULE_SERVER, ISC_LOG_ERROR,
@ -5318,6 +5309,16 @@ configure_view(dns_view_t *view, dns_viewlist_t *viewlist,
}
#ifdef HAVE_DLOPEN
if (hook_list != NULL) {
const void *hashinit = isc_hash_get_initializer();
CHECK(ns_hook_createctx(mctx, hashinit, &hctx));
INSIST(view->hooktable == NULL);
CHECK(ns_hooktable_create(view->mctx,
(ns_hooktable_t **) &view->hooktable));
view->hooktable_free = ns_hooktable_free;
}
for (element = cfg_list_first(hook_list);
element != NULL;
element = cfg_list_next(element))
@ -5325,8 +5326,8 @@ configure_view(dns_view_t *view, dns_viewlist_t *viewlist,
const cfg_obj_t *hook = cfg_listelt_value(element);
if (view->hooktable == NULL) {
ns_hooktable_create(view->mctx,
(ns_hooktable_t **) &view->hooktable);
CHECK(ns_hooktable_create(view->mctx,
(ns_hooktable_t **) &view->hooktable));
view->hooktable_free = ns_hooktable_free;
}
@ -8080,7 +8081,7 @@ load_configuration(const char *filename, named_server_t *server,
* Shut down all dyndb and hook module instances.
*/
dns_dyndb_cleanup(false);
ns_hookmodule_cleanup();
ns_hookmodule_unload_all();
/*
* Parse the global default pseudo-config file.
@ -9565,7 +9566,7 @@ shutdown_server(isc_task_t *task, isc_event_t *event) {
* Shut down all dyndb and hook module instances.
*/
dns_dyndb_cleanup(true);
ns_hookmodule_cleanup();
ns_hookmodule_unload_all();
while ((nsc = ISC_LIST_HEAD(server->cachelist)) != NULL) {
ISC_LIST_UNLINK(server->cachelist, nsc, link);

View file

@ -26,3 +26,6 @@ rm -f ns4/dsset-*
rm -f dig.out.*
rm -f ns*/named.lock
rm -f ns*/managed-keys.bind*
rm -f ns*/trusted.conf
rm -f ns*/keygen.out

View file

@ -21,10 +21,15 @@ infile=signed.db.in
zonefile=signed.db.signed
outfile=signed.db.signed
keyname1=`$KEYGEN -a $DEFAULT_ALGORITHM -b $DEFAULT_BITS -n zone $zone 2> /dev/null`
keyname2=`$KEYGEN -f KSK -a $DEFAULT_ALGORITHM -b $DEFAULT_BITS -n zone $zone 2> /dev/null`
$KEYGEN -a $DEFAULT_ALGORITHM $zone 2>&1 > /dev/null | cat_i
$KEYGEN -f KSK -a $DEFAULT_ALGORITHM $zone 2>&1 > keygen.out | cat_i
keyname=`cat keygen.out`
rm -f keygen.out
cat $infile $keyname1.key $keyname2.key >$zonefile
keyfile_to_trusted_keys $keyname > trusted.conf
cp trusted.conf ../ns2/trusted.conf
cp trusted.conf ../ns3/trusted.conf
cp trusted.conf ../ns5/trusted.conf
$SIGNER -o $zone -f $outfile $zonefile > /dev/null 2> signer.err || cat signer.err
echo_i "signed $zone"
$SIGNER -S -o $zone -f $outfile $infile > /dev/null 2> signer.err || cat signer.err
echo_i "signed zone '$zone'"

View file

@ -38,3 +38,5 @@ controls {
};
zone "." { type hint; file "hints"; };
include "trusted.conf";

View file

@ -38,3 +38,5 @@ controls {
};
zone "." { type hint; file "hints"; };
include "trusted.conf";

View file

@ -38,3 +38,5 @@ controls {
};
zone "." { type hint; file "hints"; };
include "trusted.conf";

View file

@ -38,3 +38,5 @@ controls {
};
zone "." { type hint; file "hints"; };
include "trusted.conf";

View file

@ -21,10 +21,8 @@ infile=signed.db.in
zonefile=signed.db.signed
outfile=signed.db.signed
keyname1=`$KEYGEN -a $DEFAULT_ALGORITHM -b $DEFAULT_BITS -n zone $zone 2> /dev/null`
keyname2=`$KEYGEN -f KSK -a $DEFAULT_ALGORITHM -b $DEFAULT_BITS -n zone $zone 2> /dev/null`
$KEYGEN -a $DEFAULT_ALGORITHM $zone 2>&1 > /dev/null | cat_i
$KEYGEN -f KSK -a $DEFAULT_ALGORITHM $zone 2>&1 > /dev/null | cat_i
cat $infile $keyname1.key $keyname2.key >$zonefile
$SIGNER -o $zone -f $outfile $zonefile > /dev/null 2> signer.err || cat signer.err
echo_i "signed $zone"
$SIGNER -S -o $zone -f $outfile $infile > /dev/null 2> signer.err || cat signer.err
echo_i "signed zone '$zone'"

View file

@ -43,3 +43,5 @@ controls {
};
zone "." { type hint; file "hints"; };
include "trusted.conf";

View file

@ -199,7 +199,6 @@ else
echo_i "skipped."
fi
#
# Authoritative tests against:
# filter-aaaa-on-v4 break-dnssec;
@ -380,6 +379,7 @@ n=`expr $n + 1`
echo_i "checking that AAAA is returned when only AAAA record exists, signed, recursive ($n)"
ret=0
$DIG $DIGOPTS aaaa aaaa-only.signed -b 10.53.0.2 @10.53.0.2 > dig.out.ns2.test$n || ret=1
grep "flags:.*ad.*QUERY" dig.out.ns2.test$n > /dev/null || ret=1
grep ::2 dig.out.ns2.test$n > /dev/null || ret=1
if [ $ret != 0 ]; then echo_i "failed"; fi
status=`expr $status + $ret`
@ -397,6 +397,7 @@ echo_i "checking that NODATA/NOERROR is returned when both AAAA and A records ex
ret=0
$DIG $DIGOPTS aaaa dual.signed -b 10.53.0.2 @10.53.0.2 > dig.out.ns2.test$n || ret=1
grep "ANSWER: 0" dig.out.ns2.test$n > /dev/null || ret=1
grep "flags:.*ad.*QUERY" dig.out.ns2.test$n > /dev/null && ret=1
grep "status: NOERROR" dig.out.ns2.test$n > /dev/null || ret=1
if [ $ret != 0 ]; then echo_i "failed"; fi
status=`expr $status + $ret`
@ -406,6 +407,7 @@ echo_i "checking that NODATA/NOERROR is returned when both AAAA and A records ex
ret=0
$DIG $DIGOPTS aaaa dual.unsigned -b 10.53.0.2 @10.53.0.2 > dig.out.ns2.test$n || ret=1
grep "ANSWER: 0" dig.out.ns2.test$n > /dev/null || ret=1
grep "flags:.*ad.*QUERY" dig.out.ns2.test$n > /dev/null && ret=1
grep "status: NOERROR" dig.out.ns2.test$n > /dev/null || ret=1
if [ $ret != 0 ]; then echo_i "failed"; fi
status=`expr $status + $ret`
@ -414,6 +416,7 @@ n=`expr $n + 1`
echo_i "checking that AAAA is returned when both AAAA and A records exist, signed and DO set, recursive ($n)"
ret=0
$DIG $DIGOPTS aaaa dual.signed +dnssec -b 10.53.0.2 @10.53.0.2 > dig.out.ns2.test$n || ret=1
grep "flags:.*ad.*QUERY" dig.out.ns2.test$n > /dev/null || ret=1
grep ::3 dig.out.ns2.test$n > /dev/null || ret=1
if [ $ret != 0 ]; then echo_i "failed"; fi
status=`expr $status + $ret`
@ -423,6 +426,7 @@ echo_i "checking that NODATA/NOERROR is returned when both AAAA and A records ex
ret=0
$DIG $DIGOPTS aaaa dual.unsigned +dnssec -b 10.53.0.2 @10.53.0.2 > dig.out.ns2.test$n || ret=1
grep "ANSWER: 0" dig.out.ns2.test$n > /dev/null || ret=1
grep "flags:.*ad.*QUERY" dig.out.ns2.test$n > /dev/null && ret=1
grep "status: NOERROR" dig.out.ns2.test$n > /dev/null || ret=1
if [ $ret != 0 ]; then echo_i "failed"; fi
status=`expr $status + $ret`
@ -461,6 +465,7 @@ echo_i "checking that both A and AAAA are returned when both AAAA and A records
ret=0
$DIG $DIGOPTS any dual.signed +dnssec -b 10.53.0.2 @10.53.0.2 > dig.out.ns2.test$n || ret=1
grep "status: NOERROR" dig.out.ns2.test$n > /dev/null || ret=1
grep "flags:.*ad.*QUERY" dig.out.ns2.test$n > /dev/null || ret=1
grep ::3 dig.out.ns2.test$n > /dev/null || ret=1
grep "1.0.0.3" dig.out.ns2.test$n > /dev/null || ret=1
if [ $ret != 0 ]; then echo_i "failed"; fi
@ -509,7 +514,7 @@ if [ $ret != 0 ]; then echo_i "failed"; fi
status=`expr $status + $ret`
n=`expr $n + 1`
echo_i "checking that AAAA is omitted from additional section, qtype=MX, unsigned ($n)"
echo_i "checking that AAAA is omitted from additional section, qtype=MX, unsigned, recursive ($n)"
ret=0
$DIG $DIGOPTS +add +dnssec mx unsigned -b 10.53.0.2 @10.53.0.2 > dig.out.ns2.test$n || ret=1
grep "^mx.unsigned.*AAAA" dig.out.ns2.test$n > /dev/null 2>&1 && ret=1
@ -517,15 +522,21 @@ if [ $ret != 0 ]; then echo_i "failed"; fi
status=`expr $status + $ret`
n=`expr $n + 1`
echo_i "checking that AAAA is included in additional section, qtype=MX, signed ($n)"
echo_i "checking that AAAA is included in additional section, qtype=MX, signed, recursive ($n)"
ret=0
# we need to prime the cache with addresses for the MX, since additional
# section data won't be included unless it's validated, and that doesn't
# necessarily happen otherwise.
$DIG $DIGOPTS +dnssec mx.signed @10.53.0.2 > /dev/null
$DIG $DIGOPTS +dnssec mx.signed aaaa @10.53.0.2 > /dev/null
$DIG $DIGOPTS +add +dnssec mx signed -b 10.53.0.2 @10.53.0.2 > dig.out.ns2.test$n || ret=1
grep "^mx.signed.*AAAA" dig.out.ns2.test$n > /dev/null 2>&1 || ret=1
grep "flags:.*ad.*QUERY" dig.out.ns2.test$n > /dev/null || ret=1
if [ $ret != 0 ]; then echo_i "failed"; fi
status=`expr $status + $ret`
n=`expr $n + 1`
echo_i "checking that AAAA is included in additional section, qtype=MX, unsigned, over IPv6 ($n)"
echo_i "checking that AAAA is included in additional section, qtype=MX, unsigned, recursive, over IPv6 ($n)"
if $TESTSOCK6 fd92:7065:b8e:ffff::2
then
ret=0
@ -537,7 +548,6 @@ else
echo_i "skipped."
fi
#
# Recursive tests against:
# filter-aaaa-on-v4 break-dnssec;
@ -547,6 +557,7 @@ n=`expr $n + 1`
echo_i "checking that AAAA is returned when only AAAA record exists, signed, recursive with break-dnssec ($n)"
ret=0
$DIG $DIGOPTS aaaa aaaa-only.signed -b 10.53.0.3 @10.53.0.3 > dig.out.ns3.test$n || ret=1
grep "flags:.*ad.*QUERY" dig.out.ns3.test$n > /dev/null || ret=1
grep ::2 dig.out.ns3.test$n > /dev/null || ret=1
if [ $ret != 0 ]; then echo_i "failed"; fi
status=`expr $status + $ret`
@ -564,6 +575,7 @@ echo_i "checking that NODATA/NOERROR is returned when both AAAA and A records ex
ret=0
$DIG $DIGOPTS aaaa dual.signed -b 10.53.0.3 @10.53.0.3 > dig.out.ns3.test$n || ret=1
grep "ANSWER: 0" dig.out.ns3.test$n > /dev/null || ret=1
grep "flags:.*ad.*QUERY" dig.out.ns3.test$n > /dev/null && ret=1
grep "status: NOERROR" dig.out.ns3.test$n > /dev/null || ret=1
if [ $ret != 0 ]; then echo_i "failed"; fi
status=`expr $status + $ret`
@ -573,6 +585,7 @@ echo_i "checking that NODATA/NOERROR is returned when both AAAA and A records ex
ret=0
$DIG $DIGOPTS aaaa dual.unsigned -b 10.53.0.3 @10.53.0.3 > dig.out.ns3.test$n || ret=1
grep "ANSWER: 0" dig.out.ns3.test$n > /dev/null || ret=1
grep "flags:.*ad.*QUERY" dig.out.ns3.test$n > /dev/null && ret=1
grep "status: NOERROR" dig.out.ns3.test$n > /dev/null || ret=1
if [ $ret != 0 ]; then echo_i "failed"; fi
status=`expr $status + $ret`
@ -582,6 +595,7 @@ echo_i "checking that NODATA/NOERROR is returned when both AAAA and A records ex
ret=0
$DIG $DIGOPTS aaaa dual.signed +dnssec -b 10.53.0.3 @10.53.0.3 > dig.out.ns3.test$n || ret=1
grep "ANSWER: 0" dig.out.ns3.test$n > /dev/null || ret=1
grep "flags:.*ad.*QUERY" dig.out.ns3.test$n > /dev/null && ret=1
if [ $ret != 0 ]; then echo_i "failed"; fi
status=`expr $status + $ret`
@ -590,6 +604,7 @@ echo_i "checking that NODATA/NOERROR is returned when both AAAA and A records ex
ret=0
$DIG $DIGOPTS aaaa dual.unsigned +dnssec -b 10.53.0.3 @10.53.0.3 > dig.out.ns3.test$n || ret=1
grep "ANSWER: 0" dig.out.ns3.test$n > /dev/null || ret=1
grep "flags:.*ad.*QUERY" dig.out.ns3.test$n > /dev/null && ret=1
grep "status: NOERROR" dig.out.ns3.test$n > /dev/null || ret=1
if [ $ret != 0 ]; then echo_i "failed"; fi
status=`expr $status + $ret`
@ -688,6 +703,7 @@ echo_i "checking that AAAA is omitted from additional section, qtype=MX, signed,
ret=0
$DIG $DIGOPTS +add +dnssec mx signed -b 10.53.0.3 @10.53.0.3 > dig.out.ns3.test$n || ret=1
grep "^mx.signed.*AAAA" dig.out.ns3.test$n > /dev/null 2>&1 && ret=1
grep "flags:.*ad.*QUERY" dig.out.ns3.test$n > /dev/null || ret=1
if [ $ret != 0 ]; then echo_i "failed"; fi
status=`expr $status + $ret`
@ -1047,6 +1063,7 @@ n=`expr $n + 1`
echo_i "checking that AAAA is returned when only AAAA record exists, signed, recursive ($n)"
ret=0
$DIG $DIGOPTS aaaa aaaa-only.signed -b fd92:7065:b8e:ffff::2 @fd92:7065:b8e:ffff::2 > dig.out.ns2.test$n || ret=1
grep "flags:.*ad.*QUERY" dig.out.ns2.test$n > /dev/null || ret=1
grep ::2 dig.out.ns2.test$n > /dev/null || ret=1
if [ $ret != 0 ]; then echo_i "failed"; fi
status=`expr $status + $ret`
@ -1064,6 +1081,7 @@ echo_i "checking that NODATA/NOERROR is returned when both AAAA and A records ex
ret=0
$DIG $DIGOPTS aaaa dual.signed -b fd92:7065:b8e:ffff::2 @fd92:7065:b8e:ffff::2 > dig.out.ns2.test$n || ret=1
grep "ANSWER: 0" dig.out.ns2.test$n > /dev/null || ret=1
grep "flags:.*ad.*QUERY" dig.out.ns2.test$n > /dev/null && ret=1
grep "status: NOERROR" dig.out.ns2.test$n > /dev/null || ret=1
if [ $ret != 0 ]; then echo_i "failed"; fi
status=`expr $status + $ret`
@ -1073,6 +1091,7 @@ echo_i "checking that NODATA/NOERROR is returned when both AAAA and A records ex
ret=0
$DIG $DIGOPTS aaaa dual.unsigned -b fd92:7065:b8e:ffff::2 @fd92:7065:b8e:ffff::2 > dig.out.ns2.test$n || ret=1
grep "ANSWER: 0" dig.out.ns2.test$n > /dev/null || ret=1
grep "flags:.*ad.*QUERY" dig.out.ns2.test$n > /dev/null && ret=1
grep "status: NOERROR" dig.out.ns2.test$n > /dev/null || ret=1
if [ $ret != 0 ]; then echo_i "failed"; fi
status=`expr $status + $ret`
@ -1081,6 +1100,7 @@ n=`expr $n + 1`
echo_i "checking that AAAA is returned when both AAAA and A records exist, signed and DO set, recursive ($n)"
ret=0
$DIG $DIGOPTS aaaa dual.signed +dnssec -b fd92:7065:b8e:ffff::2 @fd92:7065:b8e:ffff::2 > dig.out.ns2.test$n || ret=1
grep "flags:.*ad.*QUERY" dig.out.ns2.test$n > /dev/null || ret=1
grep ::3 dig.out.ns2.test$n > /dev/null || ret=1
if [ $ret != 0 ]; then echo_i "failed"; fi
status=`expr $status + $ret`
@ -1090,6 +1110,7 @@ echo_i "checking that NODATA/NOERROR is returned when both AAAA and A records ex
ret=0
$DIG $DIGOPTS aaaa dual.unsigned +dnssec -b fd92:7065:b8e:ffff::2 @fd92:7065:b8e:ffff::2 > dig.out.ns2.test$n || ret=1
grep "ANSWER: 0" dig.out.ns2.test$n > /dev/null || ret=1
grep "flags:.*ad.*QUERY" dig.out.ns2.test$n > /dev/null && ret=1
grep "status: NOERROR" dig.out.ns2.test$n > /dev/null || ret=1
if [ $ret != 0 ]; then echo_i "failed"; fi
status=`expr $status + $ret`
@ -1128,6 +1149,7 @@ echo_i "checking that both A and AAAA are returned when both AAAA and A records
ret=0
$DIG $DIGOPTS any dual.signed +dnssec -b fd92:7065:b8e:ffff::2 @fd92:7065:b8e:ffff::2 > dig.out.ns2.test$n || ret=1
grep "status: NOERROR" dig.out.ns2.test$n > /dev/null || ret=1
grep "flags:.*ad.*QUERY" dig.out.ns2.test$n > /dev/null || ret=1
grep ::3 dig.out.ns2.test$n > /dev/null || ret=1
grep "1.0.0.3" dig.out.ns2.test$n > /dev/null || ret=1
if [ $ret != 0 ]; then echo_i "failed"; fi
@ -1183,6 +1205,7 @@ echo_i "checking that AAAA is included in additional section, qtype=MX, signed (
ret=0
$DIG $DIGOPTS +add +dnssec mx signed -b fd92:7065:b8e:ffff::2 @fd92:7065:b8e:ffff::2 > dig.out.ns2.test$n || ret=1
grep "^mx.signed.*AAAA" dig.out.ns2.test$n > /dev/null 2>&1 || ret=1
grep "flags:.*ad.*QUERY" dig.out.ns2.test$n > /dev/null || ret=1
if [ $ret != 0 ]; then echo_i "failed"; fi
status=`expr $status + $ret`
@ -1204,6 +1227,7 @@ n=`expr $n + 1`
echo_i "checking that AAAA is returned when only AAAA record exists, signed, recursive with break-dnssec ($n)"
ret=0
$DIG $DIGOPTS aaaa aaaa-only.signed -b fd92:7065:b8e:ffff::3 @fd92:7065:b8e:ffff::3 > dig.out.ns3.test$n || ret=1
grep "flags:.*ad.*QUERY" dig.out.ns3.test$n > /dev/null || ret=1
grep ::2 dig.out.ns3.test$n > /dev/null || ret=1
if [ $ret != 0 ]; then echo_i "failed"; fi
status=`expr $status + $ret`
@ -1221,6 +1245,7 @@ echo_i "checking that NODATA/NOERROR is returned when both AAAA and A records ex
ret=0
$DIG $DIGOPTS aaaa dual.signed -b fd92:7065:b8e:ffff::3 @fd92:7065:b8e:ffff::3 > dig.out.ns3.test$n || ret=1
grep "ANSWER: 0" dig.out.ns3.test$n > /dev/null || ret=1
grep "flags:.*ad.*QUERY" dig.out.ns3.test$n > /dev/null && ret=1
grep "status: NOERROR" dig.out.ns3.test$n > /dev/null || ret=1
if [ $ret != 0 ]; then echo_i "failed"; fi
status=`expr $status + $ret`
@ -1230,6 +1255,7 @@ echo_i "checking that NODATA/NOERROR is returned when both AAAA and A records ex
ret=0
$DIG $DIGOPTS aaaa dual.unsigned -b fd92:7065:b8e:ffff::3 @fd92:7065:b8e:ffff::3 > dig.out.ns3.test$n || ret=1
grep "ANSWER: 0" dig.out.ns3.test$n > /dev/null || ret=1
grep "flags:.*ad.*QUERY" dig.out.ns3.test$n > /dev/null && ret=1
grep "status: NOERROR" dig.out.ns3.test$n > /dev/null || ret=1
if [ $ret != 0 ]; then echo_i "failed"; fi
status=`expr $status + $ret`
@ -1239,6 +1265,7 @@ echo_i "checking that NODATA/NOERROR is returned when both AAAA and A records ex
ret=0
$DIG $DIGOPTS aaaa dual.signed +dnssec -b fd92:7065:b8e:ffff::3 @fd92:7065:b8e:ffff::3 > dig.out.ns3.test$n || ret=1
grep "ANSWER: 0" dig.out.ns3.test$n > /dev/null || ret=1
grep "flags:.*ad.*QUERY" dig.out.ns3.test$n > /dev/null && ret=1
if [ $ret != 0 ]; then echo_i "failed"; fi
status=`expr $status + $ret`
@ -1247,6 +1274,7 @@ echo_i "checking that NODATA/NOERROR is returned when both AAAA and A records ex
ret=0
$DIG $DIGOPTS aaaa dual.unsigned +dnssec -b fd92:7065:b8e:ffff::3 @fd92:7065:b8e:ffff::3 > dig.out.ns3.test$n || ret=1
grep "ANSWER: 0" dig.out.ns3.test$n > /dev/null || ret=1
grep "flags:.*ad.*QUERY" dig.out.ns3.test$n > /dev/null && ret=1
grep "status: NOERROR" dig.out.ns3.test$n > /dev/null || ret=1
if [ $ret != 0 ]; then echo_i "failed"; fi
status=`expr $status + $ret`
@ -1339,6 +1367,7 @@ n=`expr $n + 1`
echo_i "checking that AAAA is omitted from additional section, qtype=MX, signed, recursive with break-dnssec ($n)"
ret=0
$DIG $DIGOPTS +add +dnssec mx signed -b fd92:7065:b8e:ffff::3 @fd92:7065:b8e:ffff::3 > dig.out.ns3.test$n || ret=1
grep "flags:.*ad.*QUERY" dig.out.ns3.test$n > /dev/null || ret=1
grep "^mx.signed.*AAAA" dig.out.ns3.test$n > /dev/null 2>&1 && ret=1
if [ $ret != 0 ]; then echo_i "failed"; fi
status=`expr $status + $ret`

View file

@ -2589,7 +2589,7 @@ dns_adb_create(isc_mem_t *mem, dns_view_t *view, isc_timermgr_t *timermgr,
result = isc_taskmgr_excltask(adb->taskmgr, &adb->excl);
if (result != ISC_R_SUCCESS) {
DP(DEF_LEVEL, "adb: task-exclusive mode unavailable, "
"intializing table sizes to %u\n",
"initializing table sizes to %u\n",
nbuckets[11]);
adb->nentries = nbuckets[11];
adb->nnames = nbuckets[11];

View file

@ -22,7 +22,7 @@ ISC_LANG_BEGINDECLS
/*!
* \brief
* Context for intializing a dyndb module.
* Context for initializing a dyndb module.
*
* This structure passes global server data to which a dyndb
* module will need access -- the server memory context, hash

View file

@ -1326,10 +1326,6 @@ LIBISCCFG_EXTERNAL_DATA cfg_type_t cfg_type_bracketed_text = {
&cfg_rep_string, NULL
};
/*%
* A bracketed address match list
*/
static cfg_type_t cfg_type_addrmatchelt;
static cfg_type_t cfg_type_negated;
@ -1416,6 +1412,9 @@ static cfg_type_t cfg_type_addrmatchelt = {
NULL, NULL
};
/*%
* A bracketed address match list
*/
LIBISCCFG_EXTERNAL_DATA cfg_type_t cfg_type_bracketed_aml = {
"bracketed_aml", cfg_parse_bracketed_list, cfg_print_bracketed_list,
cfg_doc_bracketed_list, &cfg_rep_list, &cfg_type_addrmatchelt

View file

@ -4044,6 +4044,7 @@ ns_client_newname(ns_client_t *client, isc_buffer_t *dbuf, isc_buffer_t *nbuf) {
REQUIRE((client->query.attributes & NS_QUERYATTR_NAMEBUFUSED) == 0);
CTRACE("ns_client_newname");
name = NULL;
result = dns_message_gettempname(client->message, &name);
if (result != ISC_R_SUCCESS) {

View file

@ -21,33 +21,40 @@
#include <windows.h>
#endif
#include <isc/list.h>
#include <isc/log.h>
#include <isc/mem.h>
#include <isc/mutex.h>
#include <isc/result.h>
#include <isc/once.h>
#include <isc/platform.h>
#include <isc/util.h>
#include <isc/types.h>
#include <ns/hooks.h>
#include <ns/log.h>
#include <ns/query.h>
#define CHECK(op) \
do { result = (op); \
if (result != ISC_R_SUCCESS) goto cleanup; \
do { \
result = (op); \
if (result != ISC_R_SUCCESS) { \
goto cleanup; \
} \
} while (0)
typedef struct ns_hook_module ns_hook_module_t;
struct ns_hook_module {
isc_mem_t *mctx;
void *handle;
char *filename;
char *modpath;
ns_hook_register_t *register_func;
ns_hook_destroy_t *destroy_func;
void *inst;
LINK(ns_hook_module_t) link;
};
static ns_hooklist_t hooktab[NS_QUERY_HOOKS_COUNT];
LIBNS_EXTERNAL_DATA ns_hooktable_t *ns__hook_table = &hooktab;
static ns_hooklist_t default_hooktable[NS_HOOKPOINTS_COUNT];
LIBNS_EXTERNAL_DATA ns_hooktable_t *ns__hook_table = &default_hooktable;
/*
* List of hook modules.
@ -55,40 +62,40 @@ LIBNS_EXTERNAL_DATA ns_hooktable_t *ns__hook_table = &hooktab;
* These are stored here so they can be cleaned up on shutdown.
* (The order in which they are stored is not important.)
*/
static LIST(ns_hook_module_t) hook_modules;
static isc_once_t once = ISC_ONCE_INIT;
static void
init_modules(void) {
INIT_LIST(hook_modules);
}
static ISC_LIST(ns_hook_module_t) hook_modules;
static bool hook_modules_initialized = false;
#if HAVE_DLFCN_H && HAVE_DLOPEN
static isc_result_t
load_symbol(void *handle, const char *filename,
load_symbol(void *handle, const char *modpath,
const char *symbol_name, void **symbolp)
{
const char *errmsg;
void *symbol;
REQUIRE(handle != NULL);
REQUIRE(symbolp != NULL && *symbolp == NULL);
/*
* Clear any pre-existing error conditions before running dlsym().
* (In this case, we expect dlsym() to return non-NULL values
* and will always return an error if it returns NULL, but
* this ensures that we'll report the correct error condition
* if there is one.)
*/
dlerror();
symbol = dlsym(handle, symbol_name);
if (symbol == NULL) {
errmsg = dlerror();
const char *errmsg = dlerror();
if (errmsg == NULL) {
errmsg = "returned function pointer is NULL";
}
isc_log_write(ns_lctx, NS_LOGCATEGORY_GENERAL,
NS_LOGMODULE_HOOKS, ISC_LOG_ERROR,
"failed to look upsymbol %s in "
"failed to look up symbol %s in "
"hook module '%s': %s",
symbol_name, filename, errmsg);
symbol_name, modpath, errmsg);
return (ISC_R_FAILURE);
}
dlerror();
*symbolp = symbol;
@ -96,7 +103,7 @@ load_symbol(void *handle, const char *filename,
}
static isc_result_t
load_library(isc_mem_t *mctx, const char *filename, ns_hook_module_t **hmodp) {
load_library(isc_mem_t *mctx, const char *modpath, ns_hook_module_t **hmodp) {
isc_result_t result;
void *handle = NULL;
ns_hook_module_t *hmod = NULL;
@ -107,45 +114,50 @@ load_library(isc_mem_t *mctx, const char *filename, ns_hook_module_t **hmodp) {
REQUIRE(hmodp != NULL && *hmodp == NULL);
flags = RTLD_NOW|RTLD_LOCAL;
flags = RTLD_NOW | RTLD_LOCAL;
#ifdef RTLD_DEEPBIND
flags |= RTLD_DEEPBIND;
#endif
handle = dlopen(filename, flags);
handle = dlopen(modpath, flags);
if (handle == NULL) {
CHECK(ISC_R_FAILURE);
const char *errmsg = dlerror();
if (errmsg == NULL) {
errmsg = "unknown error";
}
isc_log_write(ns_lctx, NS_LOGCATEGORY_GENERAL,
NS_LOGMODULE_HOOKS, ISC_LOG_ERROR,
"failed to dlopen() hook module '%s': %s",
modpath, errmsg);
return (ISC_R_FAILURE);
}
/* Clear dlerror */
dlerror();
CHECK(load_symbol(handle, filename, "hook_version",
CHECK(load_symbol(handle, modpath, "hook_version",
(void **)&version_func));
version = version_func(NULL);
version = version_func();
if (version < (NS_HOOK_VERSION - NS_HOOK_AGE) ||
version > NS_HOOK_VERSION)
{
isc_log_write(ns_lctx, NS_LOGCATEGORY_GENERAL,
NS_LOGMODULE_HOOKS, ISC_LOG_ERROR,
"driver API version mismatch: %d/%d",
"hook API version mismatch: %d/%d",
version, NS_HOOK_VERSION);
CHECK(ISC_R_FAILURE);
}
CHECK(load_symbol(handle, filename, "hook_register",
CHECK(load_symbol(handle, modpath, "hook_register",
(void **)&register_func));
CHECK(load_symbol(handle, filename, "hook_destroy",
CHECK(load_symbol(handle, modpath, "hook_destroy",
(void **)&destroy_func));
hmod = isc_mem_get(mctx, sizeof(*hmod));
hmod->mctx = NULL;
isc_mem_attach(mctx, &hmod->mctx);
hmod->handle = handle;
hmod->modpath = isc_mem_strdup(hmod->mctx, modpath);
hmod->register_func = register_func;
hmod->destroy_func = destroy_func;
hmod->inst = NULL;
ISC_LINK_INIT(hmod, link);
@ -158,16 +170,15 @@ cleanup:
isc_log_write(ns_lctx, NS_LOGCATEGORY_GENERAL,
NS_LOGMODULE_HOOKS, ISC_LOG_ERROR,
"failed to dynamically load "
"module '%s': %s (%s)", filename,
dlerror(), isc_result_totext(result));
"module '%s': %s", modpath,
isc_result_totext(result));
if (hmod != NULL) {
isc_mem_putanddetach(&hmod->mctx, hmod,
sizeof(*hmod));
isc_mem_putanddetach(&hmod->mctx, hmod, sizeof(*hmod));
}
if (handle != NULL) {
dlclose(handle);
(void) dlclose(handle);
}
}
@ -184,17 +195,17 @@ unload_library(ns_hook_module_t **hmodp) {
*hmodp = NULL;
if (hmod->handle != NULL) {
dlclose(hmod->handle);
(void) dlclose(hmod->handle);
}
if (hmod->filename != NULL) {
isc_mem_free(hmod->mctx, hmod->filename);
if (hmod->modpath != NULL) {
isc_mem_free(hmod->mctx, hmod->modpath);
}
isc_mem_putanddetach(&hmod->mctx, hmod, sizeof(*hmod));
}
#elif _WIN32
static isc_result_t
load_symbol(HMODULE handle, const char *filename,
load_symbol(HMODULE handle, const char *modpath,
const char *symbol_name, void **symbolp)
{
void *symbol;
@ -209,7 +220,7 @@ load_symbol(HMODULE handle, const char *filename,
NS_LOGMODULE_HOOKS, ISC_LOG_ERROR,
"failed to look up symbol %s in "
"module '%s': %d",
symbol_name, filename, errstatus);
symbol_name, modpath, errstatus);
return (ISC_R_FAILURE);
}
@ -219,7 +230,7 @@ load_symbol(HMODULE handle, const char *filename,
}
static isc_result_t
load_library(isc_mem_t *mctx, const char *filename, ns_hook_module_t **hmodp) {
load_library(isc_mem_t *mctx, const char *modpath, ns_hook_module_t **hmodp) {
isc_result_t result;
HMODULE handle;
ns_hook_module_t *hmod = NULL;
@ -230,12 +241,12 @@ load_library(isc_mem_t *mctx, const char *filename, ns_hook_module_t **hmodp) {
REQUIRE(hmodp != NULL && *hmodp == NULL);
handle = LoadLibraryA(filename);
handle = LoadLibraryA(modpath);
if (handle == NULL) {
CHECK(ISC_R_FAILURE);
}
CHECK(load_symbol(handle, filename, "hook_version",
CHECK(load_symbol(handle, modpath, "hook_version",
(void **)&version_func));
version = version_func(NULL);
@ -244,23 +255,23 @@ load_library(isc_mem_t *mctx, const char *filename, ns_hook_module_t **hmodp) {
{
isc_log_write(ns_lctx, NS_LOGCATEGORY_GENERAL,
NS_LOGMODULE_HOOKS, ISC_LOG_ERROR,
"driver API version mismatch: %d/%d",
"hook API version mismatch: %d/%d",
version, NS_HOOK_VERSION);
CHECK(ISC_R_FAILURE);
}
CHECK(load_symbol(handle, filename, "hook_register",
CHECK(load_symbol(handle, modpath, "hook_register",
(void **)&register_func));
CHECK(load_symbol(handle, filename, "hook_destroy",
CHECK(load_symbol(handle, modpath, "hook_destroy",
(void **)&destroy_func));
hmod = isc_mem_get(mctx, sizeof(*hmod));
hmod->mctx = NULL;
isc_mem_attach(mctx, &hmod->mctx);
hmod->handle = handle;
hmod->modpath = isc_mem_strdup(hmod->mctx, modpath);
hmod->register_func = register_func;
hmod->destroy_func = destroy_func;
hmod->inst = NULL;
ISC_LINK_INIT(hmod, link);
@ -273,11 +284,11 @@ cleanup:
isc_log_write(ns_lctx, NS_LOGCATEGORY_GENERAL,
NS_LOGMODULE_HOOKS, ISC_LOG_ERROR,
"failed to dynamically load "
"hook module '%s': %d (%s)", filename,
"hook module '%s': %d (%s)", modpath,
GetLastError(), isc_result_totext(result));
if (hmod != NULL) {
isc_mem_putanddetach(&hmod->mctx, hmod,
sizeof(*hmod));
isc_mem_putanddetach(&hmod->mctx, hmod, sizeof(*hmod));
}
if (handle != NULL) {
@ -301,22 +312,22 @@ unload_library(ns_hook_module_t **hmodp) {
FreeLibrary(hmod->handle);
}
if (hmod->filename != NULL) {
isc_mem_free(hmod->mctx, hmod->filename);
if (hmod->modpath != NULL) {
isc_mem_free(hmod->mctx, hmod->modpath);
}
isc_mem_putanddetach(&hmod->mctx, hmod, sizeof(*hmod));
}
#else /* HAVE_DLFCN_H || _WIN32 */
static isc_result_t
load_library(isc_mem_t *mctx, const char *filename, ns_hook_module_t **hmodp) {
load_library(isc_mem_t *mctx, const char *modpath, ns_hook_module_t **hmodp) {
UNUSED(mctx);
UNUSED(filename);
UNUSED(modpath);
UNUSED(hmodp);
isc_log_write(ns_lctx, NS_LOGCATEGORY_GENERAL,
NS_LOGMODULE_HOOKS, ISC_LOG_ERROR,
"hook module support is not hmodlemented");
"hook module support is not implemented");
return (ISC_R_NOTIMPLEMENTED);
}
@ -328,50 +339,53 @@ unload_library(ns_hook_module_t **hmodp) {
#endif /* HAVE_DLFCN_H */
isc_result_t
ns_hookmodule_load(const char *libname, const unsigned int modid,
ns_hookmodule_load(const char *modpath, const unsigned int modid,
const char *parameters,
const char *file, unsigned long line,
const char *cfg_file, unsigned long cfg_line,
const void *cfg, void *actx,
ns_hookctx_t *hctx, ns_hooktable_t *hooktable)
{
isc_result_t result;
ns_hook_module_t *module = NULL;
ns_hook_module_t *hmod = NULL;
REQUIRE(hook_modules_initialized);
REQUIRE(NS_HOOKCTX_VALID(hctx));
REQUIRE(hooktable != NULL);
isc_log_write(ns_lctx, NS_LOGCATEGORY_GENERAL,
NS_LOGMODULE_HOOKS, ISC_LOG_INFO,
"loading module '%s'", libname);
"loading module '%s'", modpath);
CHECK(load_library(hctx->mctx, libname, &module));
CHECK(module->register_func(modid, parameters, file, line,
cfg, actx, hctx, hooktable,
&module->inst));
CHECK(load_library(hctx->mctx, modpath, &hmod));
CHECK(hmod->register_func(modid, parameters, cfg_file, cfg_line,
cfg, actx, hctx, hooktable,
&hmod->inst));
APPEND(hook_modules, module, link);
result = ISC_R_SUCCESS;
ISC_LIST_APPEND(hook_modules, hmod, link);
cleanup:
if (result != ISC_R_SUCCESS && module != NULL) {
unload_library(&module);
if (result != ISC_R_SUCCESS && hmod != NULL) {
unload_library(&hmod);
}
return (result);
}
void
ns_hookmodule_cleanup(void) {
ns_hookmodule_unload_all(void) {
ns_hook_module_t *hmod, *prev;
RUNTIME_CHECK(isc_once_do(&once, init_modules) == ISC_R_SUCCESS);
if (!hook_modules_initialized) {
return;
}
hmod = ISC_LIST_TAIL(hook_modules);
while (hmod != NULL) {
prev = PREV(hmod, link);
UNLINK(hook_modules, hmod, link);
prev = ISC_LIST_PREV(hmod, link);
ISC_LIST_UNLINK(hook_modules, hmod, link);
isc_log_write(ns_lctx, NS_LOGCATEGORY_GENERAL,
NS_LOGMODULE_HOOKS, ISC_LOG_INFO,
"unloading module '%s'", hmod->filename);
"unloading module '%s'", hmod->modpath);
hmod->destroy_func(&hmod->inst);
ENSURE(hmod->inst == NULL);
unload_library(&hmod);
@ -408,8 +422,6 @@ ns_hook_destroyctx(ns_hookctx_t **hctxp) {
hctx->magic = 0;
hctx->lctx = NULL;
isc_mem_putanddetach(&hctx->mctx, hctx, sizeof(*hctx));
}
@ -417,9 +429,12 @@ void
ns_hooktable_init(ns_hooktable_t *hooktable) {
int i;
RUNTIME_CHECK(isc_once_do(&once, init_modules) == ISC_R_SUCCESS);
if (!hook_modules_initialized) {
ISC_LIST_INIT(hook_modules);
hook_modules_initialized = true;
}
for (i = 0; i < NS_QUERY_HOOKS_COUNT; i++) {
for (i = 0; i < NS_HOOKPOINTS_COUNT; i++) {
ISC_LIST_INIT((*hooktable)[i]);
}
}
@ -430,7 +445,7 @@ ns_hooktable_create(isc_mem_t *mctx, ns_hooktable_t **tablep) {
REQUIRE(tablep != NULL && *tablep == NULL);
hooktable = isc_mem_get(mctx, sizeof(ns_hooktable_t));
hooktable = isc_mem_get(mctx, sizeof(*hooktable));
ns_hooktable_init(hooktable);
@ -441,17 +456,20 @@ ns_hooktable_create(isc_mem_t *mctx, ns_hooktable_t **tablep) {
void
ns_hooktable_free(isc_mem_t *mctx, void **tablep) {
ns_hooktable_t *table;
REQUIRE(tablep != NULL && *tablep != NULL);
isc_mem_put(mctx, *tablep, sizeof(ns_hooktable_t));
table = *tablep;
*tablep = NULL;
isc_mem_put(mctx, table, sizeof(*table));
}
void
ns_hook_add(ns_hooktable_t *hooktable, ns_hookpoint_t hookpoint,
ns_hook_t *hook)
{
REQUIRE(hookpoint < NS_QUERY_HOOKS_COUNT);
REQUIRE(hookpoint < NS_HOOKPOINTS_COUNT);
REQUIRE(hook != NULL);
if (hooktable == NULL) {

View file

@ -191,7 +191,7 @@ typedef ISC_LIST(ns_client_t) client_list_t;
#define NS_CLIENTATTR_WANTDNSSEC 0x00010 /*%< include dnssec records */
#define NS_CLIENTATTR_WANTNSID 0x00020 /*%< include nameserver ID */
/* Obsolete: NS_CLIENTATTR_FILTER_AAAA 0x00040 */
/* Obsolete: define NS_CLIENTATTR_FILTER_AAAA_RC 0x00080 */
/* Obsolete: NS_CLIENTATTR_FILTER_AAAA_RC 0x00080 */
#define NS_CLIENTATTR_WANTAD 0x00100 /*%< want AD in response if possible */
#define NS_CLIENTATTR_WANTCOOKIE 0x00200 /*%< return a COOKIE */
#define NS_CLIENTATTR_HAVECOOKIE 0x00400 /*%< has a valid COOKIE */
@ -438,39 +438,39 @@ ns_client_newrdataset(ns_client_t *client);
void
ns_client_putrdataset(ns_client_t *client, dns_rdataset_t **rdatasetp);
/*%
/*%<
* Get and release temporary rdatasets in the client message;
* used in query.c and in hook modules.
*/
isc_result_t
ns_client_newnamebuf(ns_client_t *client);
/*%
/*%<
* Allocate a name buffer for the client message.
*/
dns_name_t *
ns_client_newname(ns_client_t *client, isc_buffer_t *dbuf, isc_buffer_t *nbuf);
/*%
/*%<
* Get a temporary name for the client message.
*/
isc_buffer_t *
ns_client_getnamebuf(ns_client_t *client);
/*%
/*%<
* Get a name buffer from the pool, or allocate a new one if needed.
*/
void
ns_client_keepname(ns_client_t *client, dns_name_t *name, isc_buffer_t *dbuf);
/*%
/*%<
* Adjust buffer 'dbuf' to reflect that 'name' is using space in it,
* and set client attributes appropriately.
*/
void
ns_client_releasename(ns_client_t *client, dns_name_t **namep);
/*%
/*%<
* Release 'name' back to the pool of temporary names for the client
* message. If it is using a name buffer, relinquish its exclusive
* rights on the buffer.
@ -478,20 +478,20 @@ ns_client_releasename(ns_client_t *client, dns_name_t **namep);
isc_result_t
ns_client_newdbversion(ns_client_t *client, unsigned int n);
/*%
/*%<
* Allocate 'n' new database versions for use by client queries.
*/
ns_dbversion_t *
ns_client_getdbversion(ns_client_t *client);
/*%
/*%<
* Get a free database version for use by a client query, allocating
* a new one if necessary.
*/
ns_dbversion_t *
ns_client_findversion(ns_client_t *client, dns_db_t *db);
/*%
/*%<
* Find the correct database version to use with a client query.
* If we have already done a query related to the database 'db',
* make sure subsequent queries are from the same version;

View file

@ -162,7 +162,14 @@
* called this time and foo_bar() will return ISC_R_SUCCESS.
*/
/*!
* Currently-defined hook points. So long as these are unique,
* the order in which they are declared is unimportant, but
* currently matches the order in which they are referenced in
* query.c.
*/
typedef enum {
/* hookpoints from query.c */
NS_QUERY_QCTX_INITIALIZED,
NS_QUERY_QCTX_DESTROYED,
NS_QUERY_SETUP,
@ -186,7 +193,9 @@ typedef enum {
NS_QUERY_DONE_BEGIN,
NS_QUERY_DONE_SEND,
NS_QUERY_HOOKS_COUNT /* MUST BE LAST */
/* XXX other files could be added later */
NS_HOOKPOINTS_COUNT /* MUST BE LAST */
} ns_hookpoint_t;
typedef bool
@ -199,16 +208,16 @@ typedef struct ns_hook {
} ns_hook_t;
typedef ISC_LIST(ns_hook_t) ns_hooklist_t;
typedef ns_hooklist_t ns_hooktable_t[NS_QUERY_HOOKS_COUNT];
typedef ns_hooklist_t ns_hooktable_t[NS_HOOKPOINTS_COUNT];
/*
/*%
* ns__hook_table is a global hook table, which is used if view->hooktable
* is NULL. It's intended only for use by unit tests.
*/
LIBNS_EXTERNAL_DATA extern ns_hooktable_t *ns__hook_table;
/*!
* Context for intializing a hook module.
* Context for initializing a hook module.
*
* This structure passes data to which a hook module will need
* access -- server memory context, hash initializer, log context, etc.
@ -223,7 +232,8 @@ typedef struct ns_hookctx {
} ns_hookctx_t;
#define NS_HOOKCTX_MAGIC ISC_MAGIC('H', 'k', 'c', 'x')
#define NS_HOOKCTX_VALID(d) ISC_MAGIC_VALID(d, NS_HOOKCTX_MAGIC)
#define NS_HOOKCTX_VALID(h) ISC_MAGIC_VALID(h, NS_HOOKCTX_MAGIC)
/*
* API version
*
@ -246,7 +256,7 @@ typedef isc_result_t ns_hook_register_t(const unsigned int modid,
ns_hookctx_t *hctx,
ns_hooktable_t *hooktable,
void **instp);
/*%
/*%<
* Called when registering a new module.
*
* 'parameters' contains the module configuration text.
@ -261,43 +271,68 @@ typedef isc_result_t ns_hook_register_t(const unsigned int modid,
*/
typedef void ns_hook_destroy_t(void **instp);
/*%
/*%<
* Destroy a module instance.
*
* '*instp' must be set to NULL by the function before it returns.
*/
typedef int ns_hook_version_t(unsigned int *flags);
/*%
typedef int ns_hook_version_t(void);
/*%<
* Return the API version number a hook module was compiled with.
*
* If the returned version number is no greater than than
* If the returned version number is no greater than
* NS_HOOK_VERSION, and no less than NS_HOOK_VERSION - NS_HOOK_AGE,
* then the module is API-compatible with named.
*
* 'flags' is currently unused and may be NULL, but could be used in
* the future to pass back driver capabilities or other information.
*/
/*%
* Prototypes for API functions to be defined in each module.
*/
ns_hook_destroy_t hook_destroy;
ns_hook_register_t hook_register;
ns_hook_version_t hook_version;
isc_result_t
ns_hook_createctx(isc_mem_t *mctx, ns_hookctx_t **hctxp);
void
ns_hook_destroyctx(ns_hookctx_t **hctxp);
/*%<
* Create/destroy a hook module context.
*/
isc_result_t
ns_hookmodule_load(const char *libname, const unsigned int modid,
ns_hookmodule_load(const char *modpath, const unsigned int modid,
const char *parameters,
const char *file, unsigned long line,
const char *cfg_file, unsigned long cfg_line,
const void *cfg, void *actx,
ns_hookctx_t *hctx, ns_hooktable_t *hooktable);
/*%<
* Load the hook module specified from the file 'modpath', using
* parameters 'parameters'.
*
* 'cfg_file' and 'cfg_line' specify the location of the hook module
* declaration in the configuration file.
*
* 'cfg' and 'actx' are the configuration context and ACL configuration
* context, respectively; they are passed as void * here in order to
* prevent this library from having a dependency on libisccfg).
*
* 'hctx' is the hook context and 'hooktable' is the hook table
* into which hook points should be registered.
*/
void
ns_hookmodule_cleanup(void);
ns_hookmodule_unload_all(void);
/*%<
* Unload all currently loaded hook modules.
*/
void
ns_hook_add(ns_hooktable_t *hooktable, ns_hookpoint_t hookpoint,
ns_hook_t *hook);
/*%
/*%<
* Append hook function 'hook' to the list of hooks at 'hookpoint' in
* 'hooktable'.
*
@ -310,21 +345,20 @@ ns_hook_add(ns_hooktable_t *hooktable, ns_hookpoint_t hookpoint,
void
ns_hooktable_init(ns_hooktable_t *hooktable);
/*%
/*%<
* Initialize a hook table.
*/
isc_result_t
ns_hooktable_create(isc_mem_t *mctx, ns_hooktable_t **tablep);
/*%
/*%<
* Allocate and initialize a hook table.
*/
void
ns_hooktable_free(isc_mem_t *mctx, void **tablep);
/*%
/*%<
* Free a hook table.
*/
#endif /* NS_HOOKS_H */

View file

@ -252,13 +252,13 @@ ns_query_recurse(ns_client_t *client, dns_rdatatype_t qtype, dns_name_t *qname,
isc_result_t
ns__query_sfcache(query_ctx_t *qctx);
/*%
/*%<
* (Must not be used outside this module and its associated unit tests.)
*/
isc_result_t
ns__query_start(query_ctx_t *qctx);
/*%
/*%<
* (Must not be used outside this module and its associated unit tests.)
*/

View file

@ -264,7 +264,7 @@ get_hooktab(query_ctx_t *qctx) {
* is a macro instead of an inline function; it needs to be able to use
* 'goto cleanup' regardless of the return value.)
*/
#define PROCESS_HOOK(_id, _qctx) \
#define CALL_HOOK(_id, _qctx) \
do { \
isc_result_t _res; \
ns_hooktable_t *_tab = get_hooktab(_qctx); \
@ -290,9 +290,9 @@ get_hooktab(query_ctx_t *qctx) {
* destruction calls which *must* run in every configured module.
*
* (This could be implemented as an inline void function, but is left as a
* macro for symmetry with PROCESS_HOOK above.)
* macro for symmetry with CALL_HOOK above.)
*/
#define PROCESS_ALL_HOOKS(_id, _qctx) \
#define CALL_HOOK_NORETURN(_id, _qctx) \
do { \
isc_result_t _res; \
ns_hooktable_t *_tab = get_hooktab(_qctx); \
@ -1931,22 +1931,22 @@ query_addtoname(dns_name_t *name, dns_rdataset_t *rdataset) {
static void
query_setorder(query_ctx_t *qctx, dns_name_t *name, dns_rdataset_t *rdataset) {
ns_client_t *client = qctx->client;
dns_order_t *order = client->view->order;
CTRACE(ISC_LOG_DEBUG(3), "query_setorder");
UNUSED(client);
if (qctx->view->order != NULL) {
rdataset->attributes |=
dns_order_find(qctx->view->order,
name, rdataset->type,
rdataset->rdclass);
if (order != NULL) {
rdataset->attributes |= dns_order_find(order, name,
rdataset->type,
rdataset->rdclass);
}
rdataset->attributes |= DNS_RDATASETATTR_LOADORDER;
};
/*
* Handle glue and fetch any other needed additional data for 'rdataset'
* Handle glue and fetch any other needed additional data for 'rdataset'.
*/
static void
query_additional(query_ctx_t *qctx, dns_rdataset_t *rdataset) {
@ -4855,7 +4855,7 @@ qctx_init(ns_client_t *client, dns_fetchevent_t *event,
REQUIRE(qctx != NULL);
REQUIRE(client != NULL);
memset(qctx, 0, sizeof(query_ctx_t));
memset(qctx, 0, sizeof(*qctx));
/* Set this first so CCTRACE will work */
qctx->client = client;
@ -4866,32 +4866,9 @@ qctx_init(ns_client_t *client, dns_fetchevent_t *event,
qctx->event = event;
qctx->qtype = qctx->type = qtype;
qctx->result = ISC_R_SUCCESS;
qctx->fname = NULL;
qctx->zfname = NULL;
qctx->rdataset = NULL;
qctx->zrdataset = NULL;
qctx->sigrdataset = NULL;
qctx->zsigrdataset = NULL;
qctx->zversion = NULL;
qctx->node = NULL;
qctx->znode = NULL;
qctx->db = NULL;
qctx->zdb = NULL;
qctx->version = NULL;
qctx->zone = NULL;
qctx->need_wildcardproof = false;
qctx->redirected = false;
qctx->dns64_exclude = qctx->dns64 = qctx->rpz = false;
qctx->options = 0;
qctx->resuming = false;
qctx->is_zone = false;
qctx->findcoveringnsec = qctx->view->synthfromdnssec;
qctx->is_staticstub_zone = false;
qctx->nxrewrite = false;
qctx->answer_has_ns = false;
qctx->authoritative = false;
PROCESS_ALL_HOOKS(NS_QUERY_QCTX_INITIALIZED, qctx);
CALL_HOOK_NORETURN(NS_QUERY_QCTX_INITIALIZED, qctx);
}
/*%
@ -4956,7 +4933,7 @@ qctx_freedata(query_ctx_t *qctx) {
static void
qctx_destroy(query_ctx_t *qctx) {
PROCESS_ALL_HOOKS(NS_QUERY_QCTX_DESTROYED, qctx);
CALL_HOOK_NORETURN(NS_QUERY_QCTX_DESTROYED, qctx);
dns_view_detach(&qctx->view);
}
@ -5011,7 +4988,7 @@ query_setup(ns_client_t *client, dns_rdatatype_t qtype) {
qctx_init(client, NULL, qtype, &qctx);
query_trace(&qctx);
PROCESS_HOOK(NS_QUERY_SETUP, &qctx);
CALL_HOOK(NS_QUERY_SETUP, &qctx);
/*
* If it's a SIG query, we'll iterate the node.
@ -5118,7 +5095,7 @@ ns__query_start(query_ctx_t *qctx) {
qctx->need_wildcardproof = false;
qctx->rpz = false;
PROCESS_HOOK(NS_QUERY_START_BEGIN, qctx);
CALL_HOOK(NS_QUERY_START_BEGIN, qctx);
/*
* If we require a server cookie then send back BADCOOKIE
@ -5332,7 +5309,7 @@ query_lookup(query_ctx_t *qctx) {
CCTRACE(ISC_LOG_DEBUG(3), "query_lookup");
PROCESS_HOOK(NS_QUERY_LOOKUP_BEGIN, qctx);
CALL_HOOK(NS_QUERY_LOOKUP_BEGIN, qctx);
dns_clientinfomethods_init(&cm, ns_client_sourceip);
dns_clientinfo_init(&ci, qctx->client, NULL);
@ -5512,7 +5489,7 @@ fetch_callback(isc_task_t *task, isc_event_t *event) {
query_ctx_t qctx;
/*
* Initalize a new qctx and use it to resume
* Initialize a new qctx and use it to resume
* from recursion.
*/
qctx_init(client, devent, 0, &qctx);
@ -5753,7 +5730,7 @@ query_resume(query_ctx_t *qctx) {
char tbuf[DNS_RDATATYPE_FORMATSIZE];
#endif
PROCESS_HOOK(NS_QUERY_RESUME_BEGIN, qctx);
CALL_HOOK(NS_QUERY_RESUME_BEGIN, qctx);
qctx->want_restart = false;
@ -6587,7 +6564,7 @@ query_gotanswer(query_ctx_t *qctx, isc_result_t res) {
CCTRACE(ISC_LOG_DEBUG(3), "query_gotanswer");
PROCESS_HOOK(NS_QUERY_GOT_ANSWER_BEGIN, qctx);
CALL_HOOK(NS_QUERY_GOT_ANSWER_BEGIN, qctx);
if (query_checkrrl(qctx, result) != ISC_R_SUCCESS) {
return (ns_query_done(qctx));
@ -6772,7 +6749,7 @@ query_respond_any(query_ctx_t *qctx) {
isc_result_t result;
dns_rdatatype_t onetype = 0; /* type to use for minimal-any */
PROCESS_HOOK(NS_QUERY_RESPOND_ANY_BEGIN, qctx);
CALL_HOOK(NS_QUERY_RESPOND_ANY_BEGIN, qctx);
result = dns_db_allrdatasets(qctx->db, qctx->node,
qctx->version, 0, &rdsiter);
@ -6925,14 +6902,14 @@ query_respond_any(query_ctx_t *qctx) {
}
if (found) {
PROCESS_HOOK(NS_QUERY_RESPOND_ANY_FOUND, qctx);
CALL_HOOK(NS_QUERY_RESPOND_ANY_FOUND, qctx);
if (qctx->fname != NULL) {
dns_message_puttempname(qctx->client->message,
&qctx->fname);
}
} else {
PROCESS_HOOK(NS_QUERY_RESPOND_ANY_NOT_FOUND, qctx);
CALL_HOOK(NS_QUERY_RESPOND_ANY_NOT_FOUND, qctx);
if (qctx->fname != NULL) {
dns_message_puttempname(qctx->client->message,
@ -7112,7 +7089,7 @@ query_respond(query_ctx_t *qctx) {
* other way to prevent that assertion, since the order in
* which hook modules are configured can't be enforced.)
*/
PROCESS_HOOK(NS_QUERY_RESPOND_BEGIN, qctx);
CALL_HOOK(NS_QUERY_RESPOND_BEGIN, qctx);
if (WANTDNSSEC(qctx->client) && qctx->sigrdataset != NULL) {
sigrdatasetp = &qctx->sigrdataset;
@ -7555,7 +7532,7 @@ static isc_result_t
query_notfound(query_ctx_t *qctx) {
isc_result_t result;
PROCESS_HOOK(NS_QUERY_NOTFOUND_BEGIN, qctx);
CALL_HOOK(NS_QUERY_NOTFOUND_BEGIN, qctx);
INSIST(!qctx->is_zone);
@ -7637,7 +7614,7 @@ query_prepare_delegation_response(query_ctx_t *qctx) {
dns_rdataset_t **sigrdatasetp = NULL;
bool detach = false;
PROCESS_HOOK(NS_QUERY_PREP_DELEGATION_BEGIN, qctx);
CALL_HOOK(NS_QUERY_PREP_DELEGATION_BEGIN, qctx);
/*
* qctx->fname could be released in query_addrrset(), so save a copy of
@ -7691,7 +7668,7 @@ static isc_result_t
query_zone_delegation(query_ctx_t *qctx) {
isc_result_t result;
PROCESS_HOOK(NS_QUERY_ZONE_DELEGATION_BEGIN, qctx);
CALL_HOOK(NS_QUERY_ZONE_DELEGATION_BEGIN, qctx);
/*
* If the query type is DS, look to see if we are
@ -7789,7 +7766,7 @@ static isc_result_t
query_delegation(query_ctx_t *qctx) {
isc_result_t result;
PROCESS_HOOK(NS_QUERY_DELEGATION_BEGIN, qctx);
CALL_HOOK(NS_QUERY_DELEGATION_BEGIN, qctx);
qctx->authoritative = false;
@ -8046,7 +8023,7 @@ static isc_result_t
query_nodata(query_ctx_t *qctx, isc_result_t res) {
isc_result_t result = res;
PROCESS_HOOK(NS_QUERY_NODATA_BEGIN, qctx);
CALL_HOOK(NS_QUERY_NODATA_BEGIN, qctx);
#ifdef dns64_bis_return_excluded_addresses
if (qctx->dns64)
@ -8363,7 +8340,7 @@ query_nxdomain(query_ctx_t *qctx, bool empty_wild) {
uint32_t ttl;
isc_result_t result;
PROCESS_HOOK(NS_QUERY_NXDOMAIN_BEGIN, qctx);
CALL_HOOK(NS_QUERY_NXDOMAIN_BEGIN, qctx);
INSIST(qctx->is_zone || REDIRECT(qctx->client));
@ -9259,7 +9236,7 @@ query_cname(query_ctx_t *qctx) {
dns_rdata_t rdata = DNS_RDATA_INIT;
dns_rdata_cname_t cname;
PROCESS_HOOK(NS_QUERY_CNAME_BEGIN, qctx);
CALL_HOOK(NS_QUERY_CNAME_BEGIN, qctx);
/*
* If we have a zero ttl from the cache refetch it.
@ -9392,7 +9369,7 @@ query_dname(query_ctx_t *qctx) {
isc_result_t result;
unsigned int nlabels;
PROCESS_HOOK(NS_QUERY_DNAME_BEGIN, qctx);
CALL_HOOK(NS_QUERY_DNAME_BEGIN, qctx);
/*
* Compare the current qname to the found name. We need
@ -9605,9 +9582,9 @@ query_addcname(query_ctx_t *qctx, dns_trust_t trust, dns_ttl_t ttl) {
*/
static isc_result_t
query_prepresponse(query_ctx_t *qctx) {
isc_result_t result = ISC_R_SUCCESS;
isc_result_t result;
PROCESS_HOOK(NS_QUERY_PREP_RESPONSE_BEGIN, qctx);
CALL_HOOK(NS_QUERY_PREP_RESPONSE_BEGIN, qctx);
if (WANTDNSSEC(qctx->client) &&
(qctx->fname->attributes & DNS_NAMEATTR_WILDCARD) != 0)
@ -10500,7 +10477,7 @@ ns_query_done(query_ctx_t *qctx) {
CCTRACE(ISC_LOG_DEBUG(3), "ns_query_done");
PROCESS_HOOK(NS_QUERY_DONE_BEGIN, qctx);
CALL_HOOK(NS_QUERY_DONE_BEGIN, qctx);
/*
* General cleanup.
@ -10595,7 +10572,7 @@ ns_query_done(query_ctx_t *qctx) {
qctx->result = ISC_R_FAILURE;
}
PROCESS_HOOK(NS_QUERY_DONE_SEND, qctx);
CALL_HOOK(NS_QUERY_DONE_SEND, qctx);
query_send(qctx->client);

View file

@ -46,8 +46,8 @@ ns_clientmgr_destroy
ns_hook_add
ns_hook_createctx
ns_hook_destroyctx
ns_hookmodule_cleanup
ns_hookmodule_load
ns_hookmodule_unload_all
ns_hooktable_create
ns_hooktable_free
ns_hooktable_init