if built with './configure --enable-filter-aaaa'.
Filters out AAAA answers to clients connecting
via IPv4. (This is NOT recommended for general
use.) [RT #20339]
+2732. [func] Add optional filter-aaaa-on-v4 option, available
+ if built with './configure --enable-filter-aaaa'.
+ Filters out AAAA answers to clients connecting
+ via IPv4. (This is NOT recommended for general
+ use.) [RT #20339]
+
2731. [func] Additional work on change 2709. The key parser
will now ignore unrecognized fields when the
minor version number of the private key format
* PERFORMANCE OF THIS SOFTWARE.
*/
-/* $Id: client.c,v 1.265 2009/05/07 09:41:21 fdupont Exp $ */
+/* $Id: client.c,v 1.266 2009/10/26 23:14:53 each Exp $ */
#include <config.h>
dns_compress_t cctx;
isc_boolean_t cleanup_cctx = ISC_FALSE;
unsigned char sendbuf[SEND_BUFFER_SIZE];
- unsigned int dnssec_opts;
+ unsigned int render_opts;
unsigned int preferred_glue;
isc_boolean_t opt_included = ISC_FALSE;
client->message->flags |= DNS_MESSAGEFLAG_RA;
if ((client->attributes & NS_CLIENTATTR_WANTDNSSEC) != 0)
- dnssec_opts = 0;
+ render_opts = 0;
else
- dnssec_opts = DNS_MESSAGERENDER_OMITDNSSEC;
-
+ render_opts = DNS_MESSAGERENDER_OMITDNSSEC;
+#ifdef ALLOW_FILTER_AAAA_ON_V4
+ /*
+ * filter-aaaa-on-v4 yes or break-dnssec option to suppress
+ * AAAA records
+ * We already know that request came via IPv4,
+ * that we have both AAAA and A records,
+ * and that we either have no signatures that the client wants
+ * or we are supposed to break DNSSEC.
+ */
+ if ((client->attributes & NS_CLIENTATTR_FILTER_AAAA) != 0)
+ render_opts |= DNS_MESSAGERENDER_FILTER_AAAA;
+#endif
preferred_glue = 0;
if (client->view != NULL) {
if (client->view->preferred_glue == dns_rdatatype_a)
result = dns_message_rendersection(client->message,
DNS_SECTION_ANSWER,
DNS_MESSAGERENDER_PARTIAL |
- dnssec_opts);
+ render_opts);
if (result == ISC_R_NOSPACE) {
client->message->flags |= DNS_MESSAGEFLAG_TC;
goto renderend;
result = dns_message_rendersection(client->message,
DNS_SECTION_AUTHORITY,
DNS_MESSAGERENDER_PARTIAL |
- dnssec_opts);
+ render_opts);
if (result == ISC_R_NOSPACE) {
client->message->flags |= DNS_MESSAGEFLAG_TC;
goto renderend;
goto done;
result = dns_message_rendersection(client->message,
DNS_SECTION_ADDITIONAL,
- preferred_glue | dnssec_opts);
+ preferred_glue | render_opts);
if (result != ISC_R_SUCCESS && result != ISC_R_NOSPACE)
goto done;
renderend:
* PERFORMANCE OF THIS SOFTWARE.
*/
-/* $Id: config.c,v 1.103 2009/10/10 01:47:59 each Exp $ */
+/* $Id: config.c,v 1.104 2009/10/26 23:14:53 each Exp $ */
/*! \file */
zero-no-soa-ttl-cache no;\n\
nsec3-test-zone no;\n\
"
+#ifdef ALLOW_FILTER_AAAA_ON_V4
+" filter-aaaa-on-v4 no;\n\
+"
+#endif
" /* zone */\n\
allow-query {any;};\n\
* PERFORMANCE OF THIS SOFTWARE.
*/
-/* $Id: client.h,v 1.90 2009/05/07 09:41:22 fdupont Exp $ */
+/* $Id: client.h,v 1.91 2009/10/26 23:14:53 each Exp $ */
#ifndef NAMED_CLIENT_H
#define NAMED_CLIENT_H 1
#define NS_CLIENTATTR_MULTICAST 0x08 /*%< recv'd from multicast */
#define NS_CLIENTATTR_WANTDNSSEC 0x10 /*%< include dnssec records */
#define NS_CLIENTATTR_WANTNSID 0x20 /*%< include nameserver ID */
+#ifdef ALLOW_FILTER_AAAA_ON_V4
+#define NS_CLIENTATTR_FILTER_AAAA 0x40 /*%< suppress AAAAs */
+#define NS_CLIENTATTR_FILTER_AAAA_RC 0x80 /*%< recursing for A against AAAA */
+#endif
extern unsigned int ns_client_requests;
* PERFORMANCE OF THIS SOFTWARE.
*/
-/* $Id: server.h,v 1.102 2009/10/12 20:48:11 each Exp $ */
+/* $Id: server.h,v 1.103 2009/10/26 23:14:53 each Exp $ */
#ifndef NAMED_SERVER_H
#define NAMED_SERVER_H 1
dns_name_t *session_keyname;
unsigned int session_keyalg;
isc_uint16_t session_keybits;
+#ifdef ALLOW_FILTER_AAAA_ON_V4
+ dns_v4_aaaa_t v4_aaaa;
+#endif
};
#define NS_SERVER_MAGIC ISC_MAGIC('S','V','E','R')
* PERFORMANCE OF THIS SOFTWARE.
*/
-/* $Id: query.c,v 1.328 2009/10/24 04:38:19 marka Exp $ */
+/* $Id: query.c,v 1.329 2009/10/26 23:14:53 each Exp $ */
/*! \file */
}
if (type == dns_rdatatype_any) {
+#ifdef ALLOW_FILTER_AAAA_ON_V4
+ isc_boolean_t have_aaaa, have_a, have_sig;
+
+ /*
+ * The filter-aaaa-on-v4 option should
+ * suppress AAAAs for IPv4 clients if there is an A.
+ * If we are not authoritative, assume there is a A
+ * even in if it is not in our cache. This assumption could
+ * be wrong but it is a good bet.
+ */
+ have_aaaa = ISC_FALSE;
+ have_a = !authoritative;
+ have_sig = ISC_FALSE;
+#endif
/*
* XXXRTH Need to handle zonecuts with special case
* code.
result = dns_rdatasetiter_first(rdsiter);
while (result == ISC_R_SUCCESS) {
dns_rdatasetiter_current(rdsiter, rdataset);
+#ifdef ALLOW_FILTER_AAAA_ON_V4
+ /*
+ * Notice the presence of A and AAAAs so
+ * that AAAAs can be hidden from IPv4 clients.
+ */
+ if (ns_g_server->v4_aaaa != dns_v4_aaaa_ok &&
+ client->peeraddr_valid &&
+ client->peeraddr.type.sa.sa_family == AF_INET) {
+ if (rdataset->type == dns_rdatatype_aaaa)
+ have_aaaa = ISC_TRUE;
+ else if (rdataset->type == dns_rdatatype_a)
+ have_a = ISC_TRUE;
+ }
+#endif
if (is_zone && qtype == dns_rdatatype_any &&
!dns_db_issecure(db) &&
dns_rdatatype_isdnssec(rdataset->type)) {
dns_rdataset_disassociate(rdataset);
} else if ((qtype == dns_rdatatype_any ||
rdataset->type == qtype) && rdataset->type != 0) {
+#ifdef ALLOW_FILTER_AAAA_ON_V4
+ if (dns_rdatatype_isdnssec(rdataset->type))
+ have_sig = ISC_TRUE;
+#endif
if (NOQNAME(rdataset) && WANTDNSSEC(client))
noqname = rdataset;
else
result = dns_rdatasetiter_next(rdsiter);
}
+#ifdef ALLOW_FILTER_AAAA_ON_V4
+ /*
+ * Filter AAAAs if there is an A and there is no signature
+ * or we are supposed to break DNSSEC.
+ */
+ if (have_aaaa && have_a &&
+ (!have_sig || !WANTDNSSEC(client) ||
+ ns_g_server->v4_aaaa == dns_v4_aaaa_break_dnssec))
+ client->attributes |= NS_CLIENTATTR_FILTER_AAAA;
+#endif
if (fname != NULL)
dns_message_puttempname(client->message, &fname);
* This is the "normal" case -- an ordinary question to which
* we know the answer.
*/
+#ifdef ALLOW_FILTER_AAAA_ON_V4
+ /*
+ * Optionally hide AAAAs from IPv4 clients if there is an A.
+ * We add the AAAAs now, but might refuse to render them later
+ * after DNSSEC is figured out.
+ * This could be more efficient, but the whole idea is
+ * so fundamentally wrong, unavoidably inaccurate, and
+ * unneeded that it is best to keep it as short as possible.
+ */
+ if (ns_g_server->v4_aaaa != dns_v4_aaaa_ok &&
+ client->peeraddr_valid &&
+ client->peeraddr.type.sa.sa_family == AF_INET &&
+ (!WANTDNSSEC(client) ||
+ sigrdataset == NULL ||
+ !dns_rdataset_isassociated(sigrdataset) ||
+ ns_g_server->v4_aaaa == dns_v4_aaaa_break_dnssec)) {
+ if (qtype == dns_rdatatype_aaaa) {
+ trdataset = query_newrdataset(client);
+ result = dns_db_findrdataset(db, node, version,
+ dns_rdatatype_a, 0,
+ client->now,
+ trdataset, NULL);
+ if (dns_rdataset_isassociated(trdataset))
+ dns_rdataset_disassociate(trdataset);
+ query_putrdataset(client, &trdataset);
+
+ /*
+ * We have an AAAA but the A is not in our cache.
+ * Assume any result other than DNS_R_DELEGATION
+ * or ISC_R_NOTFOUND means there is no A and
+ * so AAAAs are ok.
+ * Assume there is no A if we can't recurse
+ * for this client, although that could be
+ * the wrong answer. What else can we do?
+ * Besides, that we have the AAAA and are using
+ * this mechanism suggests that we care more
+ * about As than AAAAs and would have cached
+ * the A if it existed.
+ */
+ if (result == ISC_R_SUCCESS) {
+ client->attributes |=
+ NS_CLIENTATTR_FILTER_AAAA;
+
+ } else if (authoritative ||
+ !RECURSIONOK(client) ||
+ (result != DNS_R_DELEGATION &&
+ result != ISC_R_NOTFOUND)) {
+ client->attributes &=
+ ~NS_CLIENTATTR_FILTER_AAAA;
+ } else {
+ /*
+ * This is an ugly kludge to recurse
+ * for the A and discard the result.
+ *
+ * Continue to add the AAAA now.
+ * We'll make a note to not render it
+ * if the recursion for the A succeeds.
+ */
+ result = query_recurse(client,
+ dns_rdatatype_a,
+ NULL, NULL, resuming);
+ if (result == ISC_R_SUCCESS) {
+ client->attributes |=
+ NS_CLIENTATTR_FILTER_AAAA_RC;
+ client->query.attributes |=
+ NS_QUERYATTR_RECURSING;
+ }
+ }
+
+ } else if (qtype == dns_rdatatype_a &&
+ (client->attributes &
+ NS_CLIENTATTR_FILTER_AAAA_RC) != 0) {
+ client->attributes &=
+ ~NS_CLIENTATTR_FILTER_AAAA_RC;
+ client->attributes |=
+ NS_CLIENTATTR_FILTER_AAAA;
+ dns_rdataset_disassociate(rdataset);
+ if (sigrdataset != NULL &&
+ dns_rdataset_isassociated(sigrdataset))
+ dns_rdataset_disassociate(sigrdataset);
+ goto cleanup;
+ }
+ }
+#endif
if (sigrdataset != NULL)
sigrdatasetp = &sigrdataset;
else
* PERFORMANCE OF THIS SOFTWARE.
*/
-/* $Id: server.c,v 1.552 2009/10/20 03:15:06 marka Exp $ */
+/* $Id: server.c,v 1.553 2009/10/26 23:14:53 each Exp $ */
/*! \file */
server->flushonshutdown = ISC_FALSE;
}
+#ifdef ALLOW_FILTER_AAAA_ON_V4
+ obj = NULL;
+ result = ns_config_get(maps, "filter-aaaa-on-v4", &obj);
+ INSIST(result == ISC_R_SUCCESS);
+ if (cfg_obj_isboolean(obj)) {
+ if (cfg_obj_asboolean(obj))
+ server->v4_aaaa = dns_v4_aaaa_filter;
+ else
+ server->v4_aaaa = dns_v4_aaaa_ok;
+ } else {
+ const char *v4_aaaastr = cfg_obj_asstring(obj);
+ if (strcasecmp(v4_aaaastr, "break-dnssec") == 0)
+ server->v4_aaaa
+ = dns_v4_aaaa_break_dnssec;
+ else
+ INSIST(0);
+ }
+
+#endif
result = ISC_R_SUCCESS;
cleanup:
* PERFORMANCE OF THIS SOFTWARE.
*/
-/* $Id: config.h.in,v 1.120 2009/09/01 18:40:25 jinmei Exp $ */
+/* $Id: config.h.in,v 1.121 2009/10/26 23:14:53 each Exp $ */
/*! \file */
/* Define to empty if the keyword `volatile' does not work. Warning: valid
code using `volatile' can become incorrect without. Disable with care. */
#undef volatile
+
+/* Define to enable the "filter-aaaa-on-v4" option. */
+#undef ALLOW_FILTER_AAAA_ON_V4
+
esyscmd([sed "s/^/# /" COPYRIGHT])dnl
AC_DIVERT_POP()dnl
-AC_REVISION($Revision: 1.485 $)
+AC_REVISION($Revision: 1.486 $)
AC_INIT(lib/dns/name.c)
AC_PREREQ(2.59)
;;
esac
+#
+# Activate "filter-aaaa-on-v4" or not?
+#
+AC_ARG_ENABLE(filter-aaaa,
+ [ --enable-filter-aaaa enable filtering of AAAA records over IPv4
+ [[default=no]]],
+ enable_filter="$enableval",
+ enable_filter="no")
+case "$enable_filter" in
+ yes)
+ AC_DEFINE(ALLOW_FILTER_AAAA_ON_V4, 1,
+ [Define to enable the "filter-aaaa-on-v4" option.])
+ ;;
+ no)
+ ;;
+ *)
+ ;;
+esac
+
#
# The following sets up how non-blocking i/o is established.
# Sunos, cygwin and solaris 2.x (x<5) require special handling.
- PERFORMANCE OF THIS SOFTWARE.
-->
-<!-- File: $Id: Bv9ARM-book.xml,v 1.439 2009/10/22 03:43:16 each Exp $ -->
+<!-- File: $Id: Bv9ARM-book.xml,v 1.440 2009/10/26 23:14:53 each Exp $ -->
<book xmlns:xi="http://www.w3.org/2001/XInclude">
<title>BIND 9 Administrator Reference Manual</title>
<optional> random-device <replaceable>path_name</replaceable> ; </optional>
<optional> max-cache-size <replaceable>size_spec</replaceable> ; </optional>
<optional> match-mapped-addresses <replaceable>yes_or_no</replaceable>; </optional>
+ <optional> match-mapped-addresses <replaceable>yes_or_no</replaceable>; </optional>
+ <optional> disable-aaaa-on-v4-transport ( <replaceable>yes_or_no</replaceable> | <replaceable>break-dnssec</replaceable> ); </optional>
<optional> preferred-glue ( <replaceable>A</replaceable> | <replaceable>AAAA</replaceable> | <replaceable>NONE</replaceable> ); </optional>
<optional> edns-udp-size <replaceable>number</replaceable>; </optional>
<optional> max-udp-size <replaceable>number</replaceable>; </optional>
</listitem>
</varlistentry>
+ <varlistentry>
+ <term><command>filter-aaaa-on-v4</command></term>
+ <listitem>
+ <para>
+ This option is only available when
+ <acronym>BIND</acronym> 9 is compiled with the
+ <userinput>--with-filter-aaaa</userinput> option on the
+ "configure" command line. It is intended to help the
+ transition from IPv4 to IPv6 by not giving IPv6 addresses
+ to DNS clients unless they have connections to the IPv6
+ Internet. This is not recommended unless absolutely
+ necessary. The default is <userinput>no</userinput>.
+ </para>
+ <para>
+ If <userinput>yes</userinput>,
+ the DNS client is at an IPv4 address,
+ and if the response does not include DNSSEC signatures,
+ then all AAAA records are deleted from the response.
+ This filtering applies to all responses and not only
+ authoritative responses.
+ </para>
+ <para>
+ If <userinput>break-dnssec</userinput>,
+ then AAAA records are deleted even when dnssec is enabled.
+ As suggested by the name, this makes the response not verify,
+ because the DNSSEC protocol is designed detect deletions.
+ </para>
+ <para>
+ This mechanism can erroneously cause other servers to
+ not give AAAA records to their clients.
+ A recursing server with both IPv6 and IPv4 network connections
+ that queries an authoritative server using this mechanism
+ via IPv4 will be denied AAAA records even if its client is
+ using IPv6.
+ </para>
+ <para>
+ This mechanism is applied to authoritative as well as
+ non-authoritative records.
+ A client using IPv4 that is not allowed recursion can
+ erroneously be given AAAA records because the server is not
+ allowed to check for A records.
+ </para>
+ <para>
+ Some AAAA records are given to IPv4 clients in glue records.
+ IPv4 clients that are servers can then erroneously
+ answer requests for AAAA records received via IPv4.
+ </para>
+ <para>
+ security
+ </para>
+ </listitem>
+ </varlistentry>
+
<varlistentry>
<term><command>ixfr-from-differences</command></term>
<listitem>
* PERFORMANCE OF THIS SOFTWARE.
*/
-/* $Id: message.h,v 1.128 2009/09/01 00:22:26 jinmei Exp $ */
+/* $Id: message.h,v 1.129 2009/10/26 23:14:54 each Exp $ */
#ifndef DNS_MESSAGE_H
#define DNS_MESSAGE_H 1
additional section. */
#define DNS_MESSAGERENDER_PREFER_AAAA 0x0010 /*%< prefer AAAA records in
additional section. */
+#ifdef ALLOW_FILTER_AAAA_ON_V4
+#define DNS_MESSAGERENDER_FILTER_AAAA 0x0020 /*%< filter AAAA records */
+#endif
typedef struct dns_msgblock dns_msgblock_t;
* PERFORMANCE OF THIS SOFTWARE.
*/
-/* $Id: types.h,v 1.136 2009/09/01 00:22:27 jinmei Exp $ */
+/* $Id: types.h,v 1.137 2009/10/26 23:14:54 each Exp $ */
#ifndef DNS_TYPES_H
#define DNS_TYPES_H 1
dns_masterformat_raw = 2
} dns_masterformat_t;
+#ifdef ALLOW_FILTER_AAAA_ON_V4
+typedef enum {
+ dns_v4_aaaa_ok = 0,
+ dns_v4_aaaa_filter = 1,
+ dns_v4_aaaa_break_dnssec = 2
+} dns_v4_aaaa_t;
+
+#endif
+
/*
* These are generated by gen.c.
*/
* PERFORMANCE OF THIS SOFTWARE.
*/
-/* $Id: message.c,v 1.247 2009/01/17 23:47:42 tbox Exp $ */
+/* $Id: message.c,v 1.248 2009/10/26 23:14:54 each Exp $ */
/*! \file */
return (ISC_TRUE);
}
+#ifdef ALLOW_FILTER_AAAA_ON_V4
+/*
+ * Decide whether to not answer with an AAAA record and its RRSIG
+ */
+static inline isc_boolean_t
+norender_rdataset(const dns_rdataset_t *rdataset, unsigned int options)
+{
+ switch (rdataset->type) {
+ case dns_rdatatype_aaaa:
+ if ((options & DNS_MESSAGERENDER_FILTER_AAAA) == 0)
+ return (ISC_FALSE);
+ break;
+
+ case dns_rdatatype_rrsig:
+ if ((options & DNS_MESSAGERENDER_FILTER_AAAA) == 0 ||
+ rdataset->covers != dns_rdatatype_aaaa)
+ return (ISC_FALSE);
+ break;
+
+ default:
+ return (ISC_FALSE);
+ }
+
+ if (rdataset->rdclass != dns_rdataclass_in)
+ return (ISC_FALSE);
+
+ return (ISC_TRUE);
+}
+
+#endif
isc_result_t
dns_message_rendersection(dns_message_t *msg, dns_section_t sectionid,
unsigned int options)
preferred_glue))
goto next;
+#ifdef ALLOW_FILTER_AAAA_ON_V4
+ /*
+ * Suppress AAAAs if asked and we are
+ * not doing DNSSEC or are breaking DNSSEC.
+ * Say so in the AD bit if we break DNSSEC.
+ */
+ if (norender_rdataset(rdataset, options) &&
+ sectionid != DNS_SECTION_QUESTION) {
+ if (sectionid == DNS_SECTION_ANSWER ||
+ sectionid == DNS_SECTION_AUTHORITY)
+ msg->flags &= ~DNS_MESSAGEFLAG_AD;
+ if (OPTOUT(rdataset))
+ msg->flags &= ~DNS_MESSAGEFLAG_AD;
+ goto next;
+ }
+
+#endif
st = *(msg->buffer);
count = 0;
* PERFORMANCE OF THIS SOFTWARE.
*/
-/* $Id: namedconf.c,v 1.109 2009/10/12 23:48:02 tbox Exp $ */
+/* $Id: namedconf.c,v 1.110 2009/10/26 23:14:54 each Exp $ */
/*! \file */
static cfg_type_t cfg_type_zoneopts;
static cfg_type_t cfg_type_dynamically_loadable_zones;
static cfg_type_t cfg_type_dynamically_loadable_zones_opts;
+#ifdef ALLOW_FILTER_AAAA_ON_V4
+static cfg_type_t cfg_type_v4_aaaa;
+#endif
/*
* Clauses that can be found in a 'dynamically loadable zones' statement
{ "use-ixfr", &cfg_type_boolean, 0 },
{ "version", &cfg_type_qstringornone, 0 },
{ "flush-zones-on-shutdown", &cfg_type_boolean, 0 },
+#ifdef ALLOW_FILTER_AAAA_ON_V4
+ { "filter-aaaa-on-v4", &cfg_type_v4_aaaa, 0 },
+#endif
{ NULL, NULL, 0 }
};
&cfg_rep_string, ixfrdiff_enums,
};
+#ifdef ALLOW_FILTER_AAAA_ON_V4
+static const char *v4_aaaa_enums[] = { "break-dnssec", NULL };
+static isc_result_t
+parse_v4_aaaa(cfg_parser_t *pctx, const cfg_type_t *type,
+ cfg_obj_t **ret) {
+ return (parse_enum_or_other(pctx, type, &cfg_type_boolean, ret));
+}
+static cfg_type_t cfg_type_v4_aaaa = {
+ "v4_aaaa", parse_v4_aaaa, cfg_print_ustring,
+ doc_enum_or_other, &cfg_rep_string, v4_aaaa_enums,
+};
+
+#endif
static keyword_type_t key_kw = { "key", &cfg_type_astring };
LIBISCCFG_EXTERNAL_DATA cfg_type_t cfg_type_keyref = {