551. [func] Implemented the 'sortlist' option.

This commit is contained in:
Andreas Gustafsson 2000-11-10 03:16:26 +00:00
parent 9a6314a09a
commit febaa09184
17 changed files with 572 additions and 152 deletions

View file

@ -1,4 +1,6 @@
551. [func] Implemented the 'sortlist' option.
550. [func] Support unknown rdata types and classes.
549. [bug] "make" did not immediately abort the build when a

View file

@ -15,7 +15,7 @@
* WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
/* $Id: query.c,v 1.143 2000/11/09 19:55:16 mws Exp $ */
/* $Id: query.c,v 1.144 2000/11/10 03:16:14 gson Exp $ */
#include <config.h>
@ -2097,6 +2097,147 @@ do { \
want_restart = ISC_FALSE; \
} while (0)
/*
* Extract a network address from the RDATA of an A or AAAA
* record.
*
* Returns:
* ISC_R_SUCCESS
* ISC_R_NOTIMPLEMENTED The rdata is not a known address type.
*/
static isc_result_t
rdata_tonetaddr(dns_rdata_t *rdata, isc_netaddr_t *netaddr) {
struct in_addr ina;
struct in6_addr in6a;
switch (rdata->type) {
case dns_rdatatype_a:
INSIST(rdata->length == 4);
memcpy(&ina.s_addr, rdata->data, 4);
isc_netaddr_fromin(netaddr, &ina);
return (ISC_R_SUCCESS);
case dns_rdatatype_aaaa:
INSIST(rdata->length == 16);
memcpy(in6a.s6_addr, rdata->data, 16);
isc_netaddr_fromin6(netaddr, &in6a);
return (ISC_R_SUCCESS);
default:
return (ISC_R_NOTIMPLEMENTED);
}
}
/*
* Find the sort order of 'rdata' in the topology-like
* ACL forming the second element in a 2-element top-level
* sortlist statement.
*/
static int
sortlist_order_2element(dns_rdata_t *rdata, void *arg) {
dns_acl_t *sortacl = (dns_acl_t *) arg;
isc_netaddr_t netaddr;
int match;
if (rdata_tonetaddr(rdata, &netaddr) != ISC_R_SUCCESS)
return (INT_MAX);
(void)dns_acl_match(&netaddr, NULL, sortacl,
&ns_g_server->aclenv,
&match, NULL);
if (match > 0)
return (match);
else
return (INT_MAX - (-match));
}
/*
* Find the sort order of 'rdata' in the matching element
* of a 1-element top-level sortlist statement.
*/
static int
sortlist_order_1element(dns_rdata_t *rdata, void *arg) {
dns_aclelement_t *matchelt = (dns_aclelement_t *) arg;
isc_netaddr_t netaddr;
if (rdata_tonetaddr(rdata, &netaddr) != ISC_R_SUCCESS)
return (INT_MAX);
if (dns_aclelement_match(&netaddr, NULL, matchelt,
&ns_g_server->aclenv,
NULL)) {
return (0);
} else {
return (INT_MAX);
}
}
/*
* Find the sortlist element that applies to 'client',
* store data identifying it in '*data', and set up
* the sortlist info in in client->message appropriately.
*
* '*data' must persist until the message has been rendered.
*/
static void
setup_sortlist(ns_client_t *client) {
isc_netaddr_t netaddr;
dns_acl_t *acl = client->view->sortlist;
unsigned int i;
if (acl == NULL)
goto dont_sort;
isc_netaddr_fromsockaddr(&netaddr, &client->peeraddr);
for (i = 0; i < acl->length; i++) {
/*
* 'e' refers to the current 'top level statement'
* in the sortlist (see ARM).
*/
dns_aclelement_t *e = &acl->elements[i];
dns_aclelement_t *matchelt = NULL;
dns_acl_t *inner;
if (e->type != dns_aclelementtype_nestedacl)
goto dont_sort;
inner = e->u.nestedacl;
if (inner->length < 1 || inner->length > 2)
goto dont_sort;
if (inner->elements[0].negative)
goto dont_sort;
if (dns_aclelement_match(&netaddr, client->signer,
&inner->elements[0],
&ns_g_server->aclenv,
&matchelt)) {
if (inner->length == 2) {
dns_aclelement_t *elt1 = &inner->elements[1];
if (elt1->type != dns_aclelementtype_nestedacl)
goto dont_sort;
dns_message_setsortorder(client->message,
sortlist_order_2element,
elt1->u.nestedacl);
return;
} else {
INSIST(matchelt != NULL);
dns_message_setsortorder(client->message,
sortlist_order_1element,
matchelt);
return;
}
}
}
/* No match; don't sort. */
dont_sort:
dns_message_setsortorder(client->message, NULL, NULL);
return;
}
static void
query_find(ns_client_t *client, dns_fetchevent_t *event) {
dns_db_t *db, *zdb;
@ -3009,10 +3150,13 @@ query_find(ns_client_t *client, dns_fetchevent_t *event) {
ns_client_detach(&client);
} else if (!RECURSING(client)) {
/*
* We are done. Make a final tweak to the AA bit if the
* auth-nxdomain config option says so, then send the
* response.
* We are done. Set up sortlist data for the message
* rendering code, make a final tweak to the AA bit if the
* auth-nxdomain config option says so, then render and
* send the response.
*/
setup_sortlist(client);
if (client->message->rcode == dns_rcode_nxdomain &&
client->view->auth_nxdomain == ISC_TRUE)
client->message->flags |= DNS_MESSAGEFLAG_AA;

View file

@ -0,0 +1,23 @@
#!/bin/sh
#
# Copyright (C) 2000 Internet Software Consortium.
#
# Permission to use, copy, modify, and 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 INTERNET SOFTWARE CONSORTIUM DISCLAIMS
# ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES
# OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL INTERNET SOFTWARE
# CONSORTIUM 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: clean.sh,v 1.1 2000/11/10 03:16:16 gson Exp $
rm -f *.dig *.good

View file

@ -0,0 +1 @@
named.run

View file

@ -0,0 +1,42 @@
; Copyright (C) 2000 Internet Software Consortium.
;
; Permission to use, copy, modify, and 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 INTERNET SOFTWARE CONSORTIUM
; DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL
; IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL
; INTERNET SOFTWARE CONSORTIUM 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: example.db,v 1.1 2000/11/10 03:16:16 gson Exp $
$TTL 300 ; 5 minutes
@ IN SOA ns2.example. hostmaster.example. (
2000042795 ; serial
20 ; refresh (20 seconds)
20 ; retry (20 seconds)
1814400 ; expire (3 weeks)
3600 ; minimum (1 hour)
)
example. NS ns1.example.
ns2.example. A 10.53.0.1
; Let's see what the sortlist picks out of this...
a A 1.1.1.1
a A 1.1.1.2
a A 192.168.3.1
a A 1.1.1.3
a A 192.168.1.1
a A 1.1.1.4
b A 10.53.0.1
b A 10.53.0.2
b A 10.53.0.3
b A 10.53.0.4
b A 10.53.0.5

View file

@ -0,0 +1,46 @@
/*
* Copyright (C) 2000 Internet Software Consortium.
*
* Permission to use, copy, modify, and 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 INTERNET SOFTWARE CONSORTIUM
* DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL
* INTERNET SOFTWARE CONSORTIUM 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: named.conf,v 1.1 2000/11/10 03:16:16 gson Exp $ */
options {
query-source address 10.53.0.1;
port 5300;
pid-file "named.pid";
listen-on { 10.53.0.1; };
listen-on-v6 { none; };
recursion no;
notify yes;
sortlist {
{ 10.53.0.1; // IF 10.53.0.1
{ // THEN first fit on the
192.168.3/24; // following nets
{ 192.168.2/24; 192.168.1/24; }; }; };
{ { 10.53.0.2; 10.53.0.3; }; }; // Prefer self
};
};
zone "." {
type master;
file "root.db";
};
zone "example" {
type master;
file "example.db";
};

View file

@ -0,0 +1,30 @@
; Copyright (C) 2000 Internet Software Consortium.
;
; Permission to use, copy, modify, and 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 INTERNET SOFTWARE CONSORTIUM
; DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL
; IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL
; INTERNET SOFTWARE CONSORTIUM 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: root.db,v 1.1 2000/11/10 03:16:16 gson Exp $
$TTL 300
. IN SOA gson.nominum.com. a.root.servers.nil. (
2000042100 ; serial
600 ; refresh
600 ; retry
1200 ; expire
600 ; minimum
)
. NS a.root-servers.nil.
a.root-servers.nil. A 10.53.0.1
example. NS ns2.example.
ns2.example. A 10.53.0.2

View file

@ -0,0 +1,49 @@
#!/bin/sh
#
# Copyright (C) 2000 Internet Software Consortium.
#
# Permission to use, copy, modify, and 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 INTERNET SOFTWARE CONSORTIUM
# DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL
# INTERNET SOFTWARE CONSORTIUM 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: tests.sh,v 1.1 2000/11/10 03:16:16 gson Exp $
SYSTEMTESTTOP=..
. $SYSTEMTESTTOP/conf.sh
status=0
echo "I:test 2-element sortlist statement"
cat <<EOF >test1.good
a.example. 300 IN A 192.168.3.1
a.example. 300 IN A 192.168.1.1
EOF
$DIG +tcp +noadd +nosea +nostat +noquest +noauth +nocomm +nocmd a.example. \
@10.53.0.1 -b 10.53.0.1 -p 5300 | head -2 >test1.dig
# Note that this can't use digcomp.pl because here, the ordering of the
# result RRs is significant.
diff test1.dig test1.good || status=1
echo "I:test 1-element sortlist statement"
for n in 2 3
do
cat <<EOF >test2.good
b.example. 300 IN A 10.53.0.$n
EOF
$DIG +tcp +noadd +nosea +nostat +noquest +noauth +nocomm +nocmd \
b.example. \
@10.53.0.1 -b 10.53.0.$n -p 5300 | head -1 >test2.dig
diff test2.dig test2.good || status=1
done
echo "I:exit status: $status"
exit $status

View file

@ -15,7 +15,7 @@
* WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
/* $Id: acl.c,v 1.14 2000/08/11 01:53:46 gson Exp $ */
/* $Id: acl.c,v 1.15 2000/11/10 03:16:16 gson Exp $ */
#include <config.h>
@ -130,84 +130,17 @@ dns_acl_match(isc_netaddr_t *reqaddr,
int *match,
dns_aclelement_t **matchelt)
{
isc_result_t result;
unsigned int i;
int indirectmatch;
REQUIRE(reqaddr != NULL);
REQUIRE(matchelt == NULL || *matchelt == NULL);
for (i = 0; i < acl->length; i++) {
dns_aclelement_t *e = &acl->elements[i];
dns_acl_t *inner = NULL;
switch (e->type) {
case dns_aclelementtype_ipprefix:
if (isc_netaddr_eqprefix(reqaddr,
&e->u.ip_prefix.address,
e->u.ip_prefix.prefixlen))
goto matched;
break;
case dns_aclelementtype_keyname:
if (reqsigner != NULL &&
dns_name_equal(reqsigner, &e->u.keyname))
goto matched;
break;
case dns_aclelementtype_nestedacl:
inner = e->u.nestedacl;
nested:
result = dns_acl_match(reqaddr, reqsigner,
inner,
env,
&indirectmatch, matchelt);
if (result != ISC_R_SUCCESS)
return (result);
/*
* Treat negative matches in indirect ACLs as
* "no match".
* That way, a negated indirect ACL will never become
* a surprise positive match through double negation.
* XXXDCL this should be documented.
*/
if (indirectmatch > 0)
goto matched;
/*
* A negative indirect match may have set *matchelt,
* but we don't want it set when we return.
*/
if (matchelt != NULL)
*matchelt = NULL;
break;
case dns_aclelementtype_any:
matched:
if (dns_aclelement_match(reqaddr, reqsigner, e, env, matchelt)) {
*match = e->negative ? -(i+1) : (i+1);
if (matchelt != NULL)
*matchelt = e;
return (ISC_R_SUCCESS);
case dns_aclelementtype_localhost:
if (env != NULL && env->localhost != NULL) {
inner = env->localhost;
goto nested;
} else {
break;
}
case dns_aclelementtype_localnets:
if (env != NULL && env->localnets != NULL) {
inner = env->localnets;
goto nested;
} else {
break;
}
default:
INSIST(0);
break;
}
}
/* No match. */
@ -215,6 +148,89 @@ dns_acl_match(isc_netaddr_t *reqaddr,
return (ISC_R_SUCCESS);
}
isc_boolean_t
dns_aclelement_match(isc_netaddr_t *reqaddr,
dns_name_t *reqsigner,
dns_aclelement_t *e,
dns_aclenv_t *env,
dns_aclelement_t **matchelt)
{
dns_acl_t *inner = NULL;
int indirectmatch;
isc_result_t result;
switch (e->type) {
case dns_aclelementtype_ipprefix:
if (isc_netaddr_eqprefix(reqaddr,
&e->u.ip_prefix.address,
e->u.ip_prefix.prefixlen))
goto matched;
break;
case dns_aclelementtype_keyname:
if (reqsigner != NULL &&
dns_name_equal(reqsigner, &e->u.keyname))
goto matched;
break;
case dns_aclelementtype_nestedacl:
inner = e->u.nestedacl;
nested:
result = dns_acl_match(reqaddr, reqsigner,
inner,
env,
&indirectmatch, matchelt);
if (result != ISC_R_SUCCESS)
return (result);
/*
* Treat negative matches in indirect ACLs as
* "no match".
* That way, a negated indirect ACL will never become
* a surprise positive match through double negation.
* XXXDCL this should be documented.
*/
if (indirectmatch > 0)
goto matchelt_set;
/*
* A negative indirect match may have set *matchelt,
* but we don't want it set when we return.
*/
if (matchelt != NULL)
*matchelt = NULL;
break;
case dns_aclelementtype_any:
matched:
if (matchelt != NULL)
*matchelt = e;
matchelt_set:
return (ISC_TRUE);
case dns_aclelementtype_localhost:
if (env != NULL && env->localhost != NULL) {
inner = env->localhost;
goto nested;
} else {
break;
}
case dns_aclelementtype_localnets:
if (env != NULL && env->localnets != NULL) {
inner = env->localnets;
goto nested;
} else {
break;
}
default:
INSIST(0);
break;
}
return (ISC_FALSE);
}
void
dns_acl_attach(dns_acl_t *source, dns_acl_t **target) {
REQUIRE(DNS_ACL_VALID(source));

View file

@ -15,7 +15,7 @@
* WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
/* $Id: confctx.c,v 1.99 2000/11/08 03:53:13 marka Exp $ */
/* $Id: confctx.c,v 1.100 2000/11/10 03:16:21 gson Exp $ */
#include <config.h>
@ -515,13 +515,6 @@ dns_c_checkconfig(dns_c_ctx_t *cfg)
"option 'topology' is deprecated");
}
if (dns_c_ctx_getsortlist(cfg, &ipml) != ISC_R_NOTFOUND) {
dns_c_ipmatchlist_detach(&ipml);
isc_log_write(dns_lctx, DNS_LOGCATEGORY_CONFIG,
DNS_LOGMODULE_CONFIG, ISC_LOG_WARNING,
"option 'sortlist' is not yet implemented");
}
if (dns_c_ctx_getrrsetorderlist(cfg, &olist) != ISC_R_NOTFOUND) {
isc_log_write(dns_lctx, DNS_LOGCATEGORY_CONFIG,
DNS_LOGMODULE_CONFIG, ISC_LOG_WARNING,

View file

@ -15,7 +15,7 @@
* WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
/* $Id: acl.h,v 1.14 2000/11/07 23:43:23 bwelling Exp $ */
/* $Id: acl.h,v 1.15 2000/11/10 03:16:23 gson Exp $ */
#ifndef DNS_ACL_H
#define DNS_ACL_H 1
@ -167,6 +167,21 @@ dns_acl_match(isc_netaddr_t *reqaddr,
* ISC_R_SUCCESS Always succeeds.
*/
isc_boolean_t
dns_aclelement_match(isc_netaddr_t *reqaddr,
dns_name_t *reqsigner,
dns_aclelement_t *e,
dns_aclenv_t *env,
dns_aclelement_t **matchelt);
/*
* Like dns_acl_match, but matches against the single ACL element 'e'
* rather than a complete list and returns ISC_TRUE iff it matched.
* To determine whether the match was prositive or negative, the
* caller should examine e->negative. Since the element 'e' may be
* a reference to a named ACL or a nested ACL, the matching element
* returned through 'matchelt' is not necessarily 'e' itself.
*/
ISC_LANG_ENDDECLS
#endif /* DNS_ACL_H */

View file

@ -15,7 +15,7 @@
* WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
/* $Id: message.h,v 1.80 2000/11/10 03:13:03 gson Exp $ */
/* $Id: message.h,v 1.81 2000/11/10 03:16:24 gson Exp $ */
#ifndef DNS_MESSAGE_H
#define DNS_MESSAGE_H 1
@ -1188,6 +1188,20 @@ dns_message_getrawmessage(dns_message_t *msg);
* a pointer to a region which refers the dns message.
*/
void
dns_message_setsortorder(dns_message_t *msg, dns_rdatasetorderfunc_t order,
void *order_arg);
/*
* Define the order in which RR sets get rendered by
* dns_message_rendersection() to be the ascending order
* defined by the integer value returned by 'order' when
* given each RR and 'arg' as arguments. If 'order' and
* 'order_arg' are NULL, a default order is used.
*
* Requires:
* order_arg is NULL if and only if order is NULL.
*/
ISC_LANG_ENDDECLS
#endif /* DNS_MESSAGE_H */

View file

@ -15,7 +15,7 @@
* WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
/* $Id: types.h,v 1.97 2000/11/03 07:16:07 marka Exp $ */
/* $Id: types.h,v 1.98 2000/11/10 03:16:25 gson Exp $ */
#ifndef DNS_TYPES_H
#define DNS_TYPES_H 1
@ -280,4 +280,7 @@ typedef void
typedef void
(*dns_updatecallback_t)(void *, isc_result_t, dns_message_t *);
typedef int
(*dns_rdatasetorderfunc_t)(dns_rdata_t *rdata, void *arg);
#endif /* DNS_TYPES_H */

View file

@ -15,7 +15,7 @@
* WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
/* $Id: view.h,v 1.55 2000/11/03 18:35:31 gson Exp $ */
/* $Id: view.h,v 1.56 2000/11/10 03:16:26 gson Exp $ */
#ifndef DNS_VIEW_H
#define DNS_VIEW_H 1
@ -106,6 +106,7 @@ struct dns_view {
dns_transfer_format_t transfer_format;
dns_acl_t * queryacl;
dns_acl_t * recursionacl;
dns_acl_t * sortlist;
isc_boolean_t requestixfr;
isc_boolean_t provideixfr;
dns_ttl_t maxcachettl;

View file

@ -15,7 +15,7 @@
* WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
/* $Id: message.c,v 1.156 2000/10/27 21:56:56 bwelling Exp $ */
/* $Id: message.c,v 1.157 2000/11/10 03:16:18 gson Exp $ */
/***
*** Imports
@ -372,6 +372,8 @@ msginit(dns_message_t *m) {
m->tcp_continuation = 0;
m->verified_sig = 0;
m->verify_attempted = 0;
m->order = NULL;
m->order_arg = NULL;
}
static inline void
@ -468,7 +470,7 @@ msgresetsigs(dns_message_t *msg, isc_boolean_t replying) {
/*
* Free all but one (or everything) for this message. This is used by
* both dns_message_reset() and dns_message_parse().
* both dns_message_reset() and dns_message_destroy().
*/
static void
msgreset(dns_message_t *msg, isc_boolean_t everything) {
@ -1744,10 +1746,13 @@ dns_message_rendersection(dns_message_t *msg, dns_section_t sectionid,
st = *(msg->buffer);
count = 0;
result = dns_rdataset_towire(rdataset, name,
&msg->cctx,
msg->buffer,
&count);
result = dns_rdataset_towiresorted(rdataset,
name,
&msg->cctx,
msg->buffer,
msg->order,
msg->order_arg,
&count);
total += count;
@ -2948,3 +2953,12 @@ dns_message_getrawmessage(dns_message_t *msg) {
REQUIRE(DNS_MESSAGE_VALID(msg));
return (msg->saved);
}
void
dns_message_setsortorder(dns_message_t *msg, dns_rdatasetorderfunc_t order,
void *order_arg)
{
msg->order = order;
msg->order_arg = order_arg;
}

View file

@ -15,7 +15,7 @@
* WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
/* $Id: rdataset.c,v 1.51 2000/10/25 04:26:47 marka Exp $ */
/* $Id: rdataset.c,v 1.52 2000/11/10 03:16:19 gson Exp $ */
#include <config.h>
@ -256,25 +256,38 @@ dns_rdataset_current(dns_rdataset_t *rdataset, dns_rdata_t *rdata) {
#define MAX_SHUFFLE 32
#define WANT_FIXED(r) (((r)->attributes & DNS_RDATASETATTR_FIXEDORDER) != 0)
#define WANT_RANDOM(r) (((r)->attributes & DNS_RDATASETATTR_RANDOMIZE) != 0)
struct towire_sort {
int key;
dns_rdata_t *rdata;
};
static int
towire_compare(const void *av, const void *bv) {
const struct towire_sort *a = (const struct towire_sort *) av;
const struct towire_sort *b = (const struct towire_sort *) bv;
return (a->key - b->key);
}
isc_result_t
dns_rdataset_towire(dns_rdataset_t *rdataset,
dns_name_t *owner_name,
dns_compress_t *cctx,
isc_buffer_t *target,
unsigned int *countp)
dns_rdataset_towiresorted(dns_rdataset_t *rdataset,
dns_name_t *owner_name,
dns_compress_t *cctx,
isc_buffer_t *target,
dns_rdatasetorderfunc_t order,
void *order_arg,
unsigned int *countp)
{
dns_rdata_t rdata;
isc_region_t r;
isc_result_t result;
unsigned int i, count, tcount, choice;
unsigned int i, count;
isc_buffer_t savedbuffer, rdlen;
unsigned int headlen;
isc_boolean_t question = ISC_FALSE;
isc_boolean_t shuffle = ISC_FALSE;
dns_rdata_t shuffled[MAX_SHUFFLE];
struct towire_sort sorted[MAX_SHUFFLE];
/*
* Convert 'rdataset' to wire format, compressing names as specified
@ -283,6 +296,7 @@ dns_rdataset_towire(dns_rdataset_t *rdataset,
REQUIRE(DNS_RDATASET_VALID(rdataset));
REQUIRE(countp != NULL);
REQUIRE((order == NULL) == (order_arg == NULL));
count = 0;
if ((rdataset->attributes & DNS_RDATASETATTR_QUESTION) != 0) {
@ -304,60 +318,64 @@ dns_rdataset_towire(dns_rdataset_t *rdataset,
return (result);
}
choice = 0;
if (!question && count > 1 && !WANT_FIXED(rdataset)) {
/*
* We'll only shuffle if we've got enough slots in our
* deck.
*
* There's no point to shuffling SIGs.
*/
if (!question &&
count > 1 &&
!WANT_FIXED(rdataset) &&
count <= MAX_SHUFFLE &&
rdataset->type != dns_rdatatype_sig)
{
shuffle = ISC_TRUE;
/*
* We'll only shuffle if we've got enough slots in our
* deck.
*
* There's no point to shuffling SIGs.
* First we get handles to all of the rdata.
*/
if (count <= MAX_SHUFFLE &&
rdataset->type != dns_rdatatype_sig) {
shuffle = ISC_TRUE;
i = 0;
do {
INSIST(i < count);
dns_rdata_init(&shuffled[i]);
dns_rdataset_current(rdataset, &shuffled[i]);
i++;
result = dns_rdataset_next(rdataset);
} while (result == ISC_R_SUCCESS);
if (result != ISC_R_NOMORE)
return (result);
INSIST(i == count);
/*
* Now we shuffle.
*/
if (order != NULL) {
/*
* First we get handles to all of the rdata.
* Sorted order.
*/
i = 0;
do {
INSIST(i < count);
dns_rdata_init(&shuffled[i]);
dns_rdataset_current(rdataset, &shuffled[i]);
i++;
result = dns_rdataset_next(rdataset);
} while (result == ISC_R_SUCCESS);
if (result != ISC_R_NOMORE)
return (result);
INSIST(i == count);
for (i = 0; i < count; i++) {
sorted[i].key = (*order)(&shuffled[i],
order_arg);
sorted[i].rdata = &shuffled[i];
}
qsort(sorted, count, sizeof(sorted[0]),
towire_compare);
} else {
/*
* Now we shuffle.
* "Cyclic" order.
*/
if (WANT_RANDOM(rdataset)) {
/*
* "Random" order.
*/
tcount = count;
for (i = 0; i < count; i++) {
choice = (((unsigned int)rand()) >> 3)
% tcount;
rdata = shuffled[i];
shuffled[i] = shuffled[i + choice];
shuffled[i + choice] = rdata;
tcount--;
}
choice = 0;
} else {
/*
* "Cyclic" order.
*/
choice = (((unsigned int)rand()) >> 3) % count;
unsigned int j = (((unsigned int)rand()) >> 3) % count;
for (i = 0; i < count; i++) {
sorted[j].key = 0; /* Unused */
sorted[j].rdata = &shuffled[i];
j++;
if (j == count)
j = 0; /* Wrap around. */
}
}
}
savedbuffer = *target;
i = choice;
tcount = 0;
i = 0;
do {
/*
@ -391,7 +409,7 @@ dns_rdataset_towire(dns_rdataset_t *rdataset,
* Copy out the rdata
*/
if (shuffle)
rdata = shuffled[i];
rdata = *(sorted[i].rdata);
else {
dns_rdata_init(&rdata);
dns_rdataset_current(rdataset, &rdata);
@ -408,18 +426,13 @@ dns_rdataset_towire(dns_rdataset_t *rdataset,
if (shuffle) {
i++;
/*
* Wrap around in case we're doing cyclic ordering.
*/
if (i == count)
i = 0;
tcount++;
if (tcount == count)
result = ISC_R_NOMORE;
else
result = ISC_R_SUCCESS;
} else
} else {
result = dns_rdataset_next(rdataset);
}
} while (result == ISC_R_SUCCESS);
if (result != ISC_R_NOMORE)
@ -438,6 +451,17 @@ dns_rdataset_towire(dns_rdataset_t *rdataset,
return (result);
}
isc_result_t
dns_rdataset_towire(dns_rdataset_t *rdataset,
dns_name_t *owner_name,
dns_compress_t *cctx,
isc_buffer_t *target,
unsigned int *countp)
{
return (dns_rdataset_towiresorted(rdataset, owner_name, cctx, target,
NULL, NULL, countp));
}
isc_result_t
dns_rdataset_additionaldata(dns_rdataset_t *rdataset,
dns_additionaldatafunc_t add, void *arg)

View file

@ -15,7 +15,7 @@
* WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
/* $Id: view.c,v 1.84 2000/11/03 18:27:31 gson Exp $ */
/* $Id: view.c,v 1.85 2000/11/10 03:16:20 gson Exp $ */
#include <config.h>
@ -156,6 +156,7 @@ dns_view_create(isc_mem_t *mctx, dns_rdataclass_t rdclass,
view->transfer_format = dns_one_answer;
view->queryacl = NULL;
view->recursionacl = NULL;
view->sortlist = NULL;
view->requestixfr = ISC_TRUE;
view->provideixfr = ISC_TRUE;
view->maxcachettl = 7 * 24 * 3600;
@ -248,6 +249,8 @@ destroy(dns_view_t *view) {
dns_acl_detach(&view->queryacl);
if (view->recursionacl != NULL)
dns_acl_detach(&view->recursionacl);
if (view->sortlist != NULL)
dns_acl_detach(&view->sortlist);
dns_keytable_detach(&view->trustedkeys);
dns_keytable_detach(&view->secroots);
dns_fwdtable_destroy(&view->fwdtable);