diff --git a/CHANGES b/CHANGES index 33294d8b36..c8ef33fed3 100644 --- a/CHANGES +++ b/CHANGES @@ -1,3 +1,9 @@ +1234. [bug] 'rrset-order' and 'sortlist' should be additive + not exclusive. + +1223. [func] 'rrset-order' partially works 'cyclic' and 'random' + are supported. + 1222. [bug] Specifying 'port *' did not always result in a system selected (non-reserved) port being used. [RT #2537] diff --git a/bin/named/config.c b/bin/named/config.c index 557244b2dc..08367cfd7c 100644 --- a/bin/named/config.c +++ b/bin/named/config.c @@ -15,7 +15,7 @@ * WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ -/* $Id: config.c,v 1.28 2002/03/06 23:52:38 marka Exp $ */ +/* $Id: config.c,v 1.29 2002/03/07 13:46:35 marka Exp $ */ #include @@ -35,6 +35,7 @@ #include #include #include +#include #include #include @@ -218,6 +219,27 @@ ns_config_getclass(cfg_obj_t *classobj, dns_rdataclass_t defclass, return (result); } +isc_result_t +ns_config_gettype(cfg_obj_t *typeobj, dns_rdatatype_t deftype, + dns_rdatatype_t *typep) { + char *str; + isc_textregion_t r; + isc_result_t result; + + if (!cfg_obj_isstring(typeobj)) { + *typep = deftype; + return (ISC_R_SUCCESS); + } + str = cfg_obj_asstring(typeobj); + r.base = str; + r.length = strlen(str); + result = dns_rdatatype_fromtext(typep, &r); + if (result != ISC_R_SUCCESS) + cfg_obj_log(typeobj, ns_g_lctx, ISC_LOG_ERROR, + "unknown type '%s'", str); + return (result); +} + dns_zonetype_t ns_config_getzonetype(cfg_obj_t *zonetypeobj) { dns_zonetype_t ztype = dns_zone_none; diff --git a/bin/named/include/named/config.h b/bin/named/include/named/config.h index e92aef51ac..9b767e3bad 100644 --- a/bin/named/include/named/config.h +++ b/bin/named/include/named/config.h @@ -15,7 +15,7 @@ * WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ -/* $Id: config.h,v 1.4 2001/08/09 17:21:06 gson Exp $ */ +/* $Id: config.h,v 1.5 2002/03/07 13:46:41 marka Exp $ */ #ifndef NAMED_CONFIG_H #define NAMED_CONFIG_H 1 @@ -38,6 +38,10 @@ isc_result_t ns_config_getclass(cfg_obj_t *classobj, dns_rdataclass_t defclass, dns_rdataclass_t *classp); +isc_result_t +ns_config_gettype(cfg_obj_t *typeobj, dns_rdatatype_t deftype, + dns_rdatatype_t *typep); + dns_zonetype_t ns_config_getzonetype(cfg_obj_t *zonetypeobj); diff --git a/bin/named/query.c b/bin/named/query.c index 8d63a6e64b..8d9a50aba5 100644 --- a/bin/named/query.c +++ b/bin/named/query.c @@ -15,7 +15,7 @@ * WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ -/* $Id: query.c,v 1.217 2002/02/20 03:33:18 marka Exp $ */ +/* $Id: query.c,v 1.218 2002/03/07 13:46:38 marka Exp $ */ #include @@ -29,6 +29,7 @@ #include #include #include +#include #include #include #include @@ -1536,6 +1537,10 @@ query_addrdataset(ns_client_t *client, dns_name_t *fname, ISC_LIST_APPEND(fname->list, rdataset, link); + if (client->view->order != NULL) + rdataset->attributes |= dns_order_find(client->view->order, + fname, rdataset->type, + rdataset->rdclass); if (NOADDITIONAL(client)) return; diff --git a/bin/named/server.c b/bin/named/server.c index 9a6cd1cf90..5dd913affd 100644 --- a/bin/named/server.c +++ b/bin/named/server.c @@ -15,7 +15,7 @@ * WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ -/* $Id: server.c,v 1.371 2002/02/20 03:33:21 marka Exp $ */ +/* $Id: server.c,v 1.372 2002/03/07 13:46:40 marka Exp $ */ #include @@ -47,8 +47,10 @@ #include #include #include +#include #include #include +#include #include #include #include @@ -404,6 +406,56 @@ get_view_querysource_dispatch(cfg_obj_t **maps, return (ISC_R_SUCCESS); } +static isc_result_t +configure_order(dns_order_t *order, cfg_obj_t *ent) { + dns_rdataclass_t rdclass; + dns_rdatatype_t rdtype; + cfg_obj_t *obj; + dns_fixedname_t fixed; + unsigned int mode = 0; + const char *str; + isc_buffer_t b; + isc_result_t result; + + result = ns_config_getclass(cfg_tuple_get(ent, "class"), + dns_rdataclass_any, &rdclass); + if (result != ISC_R_SUCCESS) + return (result); + + result = ns_config_gettype(cfg_tuple_get(ent, "type"), + dns_rdatatype_any, &rdtype); + if (result != ISC_R_SUCCESS) + return (result); + + obj = cfg_tuple_get(ent, "name"); + if (cfg_obj_isstring(obj)) + str = cfg_obj_asstring(obj); + else + str = "*"; + isc_buffer_init(&b, str, strlen(str)); + isc_buffer_add(&b, strlen(str)); + dns_fixedname_init(&fixed); + result = dns_name_fromtext(dns_fixedname_name(&fixed), &b, + dns_rootname, ISC_FALSE, NULL); + if (result != ISC_R_SUCCESS) + return (result); + + obj = cfg_tuple_get(ent, "ordering"); + INSIST(cfg_obj_isstring(obj)); + str = cfg_obj_asstring(obj); + if (!strcasecmp(str, "fixed")) + mode = DNS_RDATASETATTR_FIXEDORDER; + else if (!strcasecmp(str, "random")) + mode = DNS_RDATASETATTR_RANDOMIZE; + else if (!strcasecmp(str, "cyclic")) + mode = 0; + else + INSIST(0); + + return (dns_order_add(order, dns_fixedname_name(&fixed), + rdtype, rdclass, mode)); +} + static isc_result_t configure_peer(cfg_obj_t *cpeer, isc_mem_t *mctx, dns_peer_t **peerp) { isc_sockaddr_t *sa; @@ -510,6 +562,7 @@ configure_view(dns_view_t *view, cfg_obj_t *config, cfg_obj_t *vconfig, isc_boolean_t reused_cache = ISC_FALSE; int i; char *str; + dns_order_t *order = NULL; REQUIRE(DNS_VIEW_VALID(view)); @@ -741,6 +794,28 @@ configure_view(dns_view_t *view, cfg_obj_t *config, cfg_obj_t *vconfig, view->peers = newpeers; /* Transfer ownership. */ } + /* + * Configure the views rrset-order. + */ + { + cfg_obj_t *rrsetorder = NULL; + cfg_listelt_t *element; + + (void)ns_config_get(maps, "rrset-order", &rrsetorder); + CHECK(dns_order_create(mctx, &order)); + for (element = cfg_list_first(rrsetorder); + element != NULL; + element = cfg_list_next(element)) + { + cfg_obj_t *ent = cfg_listelt_value(element); + + CHECK(configure_order(order, ent)); + } + if (view->order != NULL) + dns_order_detach(&view->order); + dns_order_attach(order, &view->order); + dns_order_detach(&order); + } /* * Copy the aclenv object. */ @@ -863,6 +938,8 @@ configure_view(dns_view_t *view, cfg_obj_t *config, cfg_obj_t *vconfig, result = ISC_R_SUCCESS; cleanup: + if (order != NULL) + dns_order_detach(&order); if (cmctx != NULL) isc_mem_detach(&cmctx); diff --git a/lib/dns/include/dns/view.h b/lib/dns/include/dns/view.h index 20f7e9164f..9b92440d11 100644 --- a/lib/dns/include/dns/view.h +++ b/lib/dns/include/dns/view.h @@ -15,7 +15,7 @@ * WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ -/* $Id: view.h,v 1.76 2001/11/27 04:06:15 marka Exp $ */ +/* $Id: view.h,v 1.77 2002/03/07 13:46:34 marka Exp $ */ #ifndef DNS_VIEW_H #define DNS_VIEW_H 1 @@ -100,6 +100,7 @@ struct dns_view { dns_tsig_keyring_t * statickeys; dns_tsig_keyring_t * dynamickeys; dns_peerlist_t * peers; + dns_order_t * order; dns_fwdtable_t * fwdtable; isc_boolean_t recursion; isc_boolean_t auth_nxdomain; diff --git a/lib/dns/order.c b/lib/dns/order.c index 536f17e4b5..0c719fe43b 100644 --- a/lib/dns/order.c +++ b/lib/dns/order.c @@ -15,7 +15,7 @@ * WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ -/* $Id: order.c,v 1.2 2002/03/07 07:48:46 bwelling Exp $ */ +/* $Id: order.c,v 1.3 2002/03/07 13:46:30 marka Exp $ */ #include #include @@ -63,6 +63,7 @@ dns_order_create(isc_mem_t *mctx, dns_order_t **orderp) { order->mctx = NULL; isc_mem_attach(mctx, &order->mctx); order->magic = DNS_ORDER_MAGIC; + *orderp = order; return (ISC_R_SUCCESS); } diff --git a/lib/dns/rdataset.c b/lib/dns/rdataset.c index 7766cf8466..81b30ec349 100644 --- a/lib/dns/rdataset.c +++ b/lib/dns/rdataset.c @@ -15,7 +15,7 @@ * WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ -/* $Id: rdataset.c,v 1.61 2002/02/20 03:34:18 marka Exp $ */ +/* $Id: rdataset.c,v 1.62 2002/03/07 13:46:31 marka Exp $ */ #include @@ -256,6 +256,7 @@ 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; @@ -279,7 +280,7 @@ towiresorted(dns_rdataset_t *rdataset, dns_name_t *owner_name, dns_rdata_t rdata = DNS_RDATA_INIT; isc_region_t r; isc_result_t result; - unsigned int i, count, added; + unsigned int i, count, added, choice; isc_buffer_t savedbuffer, rdlen, rrbuffer; unsigned int headlen; isc_boolean_t question = ISC_FALSE; @@ -330,7 +331,7 @@ towiresorted(dns_rdataset_t *rdataset, dns_name_t *owner_name, */ if (!question && count > 1 && - !WANT_FIXED(rdataset) && + (!WANT_FIXED(rdataset) || order != NULL) && count <= MAX_SHUFFLE && rdataset->type != dns_rdatatype_sig) { @@ -349,33 +350,61 @@ towiresorted(dns_rdataset_t *rdataset, dns_name_t *owner_name, if (result != ISC_R_NOMORE) return (result); INSIST(i == count); + /* * Now we shuffle. */ - if (order != NULL) { + if (WANT_FIXED(rdataset)) { /* - * Sorted order. + * 'Fixed' order. */ + INSIST(order != NULL); 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 if (WANT_RANDOM(rdataset)) { + /* + * 'Random' order. + */ + for (i = 0; i < count; i++) { + dns_rdata_t rdata; + choice = i + (((u_int)rand()>>3) % (count - i)); + rdata = shuffled[i]; + shuffled[i] = shuffled[choice]; + shuffled[choice] = rdata; + if (order != NULL) + sorted[i].key = (*order)(&shuffled[i], + order_arg); + else + sorted[i].key = 0; /* Unused */ + sorted[i].rdata = &shuffled[i]; + } } else { /* * "Cyclic" order. */ unsigned int j = (((unsigned int)rand()) >> 3) % count; for (i = 0; i < count; i++) { - sorted[j].key = 0; /* Unused */ + if (order != NULL) + sorted[i].key = (*order)(&shuffled[i], + order_arg); + else + sorted[j].key = 0; /* Unused */ sorted[j].rdata = &shuffled[i]; j++; if (j == count) j = 0; /* Wrap around. */ } } + + /* + * Sorted order. + */ + if (order != NULL) + qsort(sorted, count, sizeof(sorted[0]), + towire_compare); } savedbuffer = *target; diff --git a/lib/dns/view.c b/lib/dns/view.c index 81e795a975..7545b26bc7 100644 --- a/lib/dns/view.c +++ b/lib/dns/view.c @@ -15,7 +15,7 @@ * WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ -/* $Id: view.c,v 1.109 2001/11/30 01:59:23 gson Exp $ */ +/* $Id: view.c,v 1.110 2002/03/07 13:46:33 marka Exp $ */ #include @@ -32,6 +32,7 @@ #include #include #include +#include #include #include #include @@ -139,6 +140,7 @@ dns_view_create(isc_mem_t *mctx, dns_rdataclass_t rdclass, if (result != ISC_R_SUCCESS) goto cleanup_fwdtable; view->peers = NULL; + view->order = NULL; /* * Initialize configuration data with default values. @@ -159,10 +161,14 @@ dns_view_create(isc_mem_t *mctx, dns_rdataclass_t rdclass, view->maxncachettl = 3 * 3600; view->dstport = 53; - result = dns_peerlist_new(view->mctx, &view->peers); + result = dns_order_create(view->mctx, &view->order); if (result != ISC_R_SUCCESS) goto cleanup_dynkeys; + result = dns_peerlist_new(view->mctx, &view->peers); + if (result != ISC_R_SUCCESS) + goto cleanup_order; + result = dns_aclenv_init(view->mctx, &view->aclenv); if (result != ISC_R_SUCCESS) goto cleanup_peerlist; @@ -186,6 +192,9 @@ dns_view_create(isc_mem_t *mctx, dns_rdataclass_t rdclass, cleanup_peerlist: dns_peerlist_detach(&view->peers); + cleanup_order: + dns_order_detach(&view->order); + cleanup_dynkeys: dns_tsigkeyring_destroy(&view->dynamickeys); @@ -222,6 +231,8 @@ destroy(dns_view_t *view) { REQUIRE(ADBSHUTDOWN(view)); REQUIRE(REQSHUTDOWN(view)); + if (view->order != NULL) + dns_order_detach(&view->order); if (view->peers != NULL) dns_peerlist_detach(&view->peers); if (view->dynamickeys != NULL)