mirror of
https://gitlab.isc.org/isc-projects/bind9
synced 2025-09-01 06:55:30 +00:00
2604. [func] Add support for DNS rebinding attack prevention through
new options, deny-answer-addresses and deny-answer-aliases. Based on contributed code from JD Nurmi, Google. [RT #18192]
This commit is contained in:
5
CHANGES
5
CHANGES
@@ -1,3 +1,8 @@
|
|||||||
|
2604. [func] Add support for DNS rebinding attack prevention through
|
||||||
|
new options, deny-answer-addresses and
|
||||||
|
deny-answer-aliases. Based on contributed code from
|
||||||
|
JD Nurmi, Google. [RT #18192]
|
||||||
|
|
||||||
2603. [port] win32: handle .exe extension of named-checkzone and
|
2603. [port] win32: handle .exe extension of named-checkzone and
|
||||||
named-comilezone argv[0] names under windows.
|
named-comilezone argv[0] names under windows.
|
||||||
[RT #19767]
|
[RT #19767]
|
||||||
|
2
README
2
README
@@ -54,6 +54,8 @@ BIND 9.7.0
|
|||||||
internal information about query failures, especially about
|
internal information about query failures, especially about
|
||||||
server failures.
|
server failures.
|
||||||
|
|
||||||
|
Add support for DNS rebinding attack prevention.
|
||||||
|
|
||||||
BIND 9.6.0
|
BIND 9.6.0
|
||||||
|
|
||||||
BIND 9.6.0 includes a number of changes from BIND 9.5 and earlier
|
BIND 9.6.0 includes a number of changes from BIND 9.5 and earlier
|
||||||
|
@@ -1,21 +1,3 @@
|
|||||||
/*
|
|
||||||
* Copyright (C) 2009 Internet Systems Consortium, Inc. ("ISC")
|
|
||||||
*
|
|
||||||
* Permission to use, copy, modify, and/or distribute this software for any
|
|
||||||
* purpose with or without fee is hereby granted, provided that the above
|
|
||||||
* copyright notice and this permission notice appear in all copies.
|
|
||||||
*
|
|
||||||
* THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
|
|
||||||
* REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
|
|
||||||
* AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
|
|
||||||
* INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
|
|
||||||
* LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
|
|
||||||
* OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
|
|
||||||
* PERFORMANCE OF THIS SOFTWARE.
|
|
||||||
*/
|
|
||||||
|
|
||||||
/* $Id: bind.keys.h,v 1.3 2009/03/05 23:47:35 tbox Exp $ */
|
|
||||||
|
|
||||||
#define TRUSTED_KEYS "\
|
#define TRUSTED_KEYS "\
|
||||||
trusted-keys {\n\
|
trusted-keys {\n\
|
||||||
# NOTE: This key expires September 2009 \n\
|
# NOTE: This key expires September 2009 \n\
|
||||||
|
@@ -15,7 +15,7 @@
|
|||||||
* PERFORMANCE OF THIS SOFTWARE.
|
* PERFORMANCE OF THIS SOFTWARE.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/* $Id: server.c,v 1.530 2009/03/04 23:48:01 tbox Exp $ */
|
/* $Id: server.c,v 1.531 2009/05/29 22:22:35 jinmei Exp $ */
|
||||||
|
|
||||||
/*! \file */
|
/*! \file */
|
||||||
|
|
||||||
@@ -278,8 +278,8 @@ end_reserved_dispatches(ns_server_t *server, isc_boolean_t all);
|
|||||||
*/
|
*/
|
||||||
static isc_result_t
|
static isc_result_t
|
||||||
configure_view_acl(const cfg_obj_t *vconfig, const cfg_obj_t *config,
|
configure_view_acl(const cfg_obj_t *vconfig, const cfg_obj_t *config,
|
||||||
const char *aclname, cfg_aclconfctx_t *actx,
|
const char *aclname, const char *acltuplename,
|
||||||
isc_mem_t *mctx, dns_acl_t **aclp)
|
cfg_aclconfctx_t *actx, isc_mem_t *mctx, dns_acl_t **aclp)
|
||||||
{
|
{
|
||||||
isc_result_t result;
|
isc_result_t result;
|
||||||
const cfg_obj_t *maps[3];
|
const cfg_obj_t *maps[3];
|
||||||
@@ -305,13 +305,21 @@ configure_view_acl(const cfg_obj_t *vconfig, const cfg_obj_t *config,
|
|||||||
*/
|
*/
|
||||||
return (ISC_R_SUCCESS);
|
return (ISC_R_SUCCESS);
|
||||||
|
|
||||||
|
if (acltuplename != NULL) {
|
||||||
|
/*
|
||||||
|
* If the ACL is given in an optional tuple, retrieve it.
|
||||||
|
* The parser should have ensured that a valid object be
|
||||||
|
* returned.
|
||||||
|
*/
|
||||||
|
aclobj = cfg_tuple_get(aclobj, acltuplename);
|
||||||
|
}
|
||||||
|
|
||||||
result = cfg_acl_fromconfig(aclobj, config, ns_g_lctx,
|
result = cfg_acl_fromconfig(aclobj, config, ns_g_lctx,
|
||||||
actx, mctx, 0, aclp);
|
actx, mctx, 0, aclp);
|
||||||
|
|
||||||
return (result);
|
return (result);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/*%
|
/*%
|
||||||
* Configure a sortlist at '*aclp'. Essentially the same as
|
* Configure a sortlist at '*aclp'. Essentially the same as
|
||||||
* configure_view_acl() except it calls cfg_acl_fromconfig with a
|
* configure_view_acl() except it calls cfg_acl_fromconfig with a
|
||||||
@@ -355,6 +363,80 @@ configure_view_sortlist(const cfg_obj_t *vconfig, const cfg_obj_t *config,
|
|||||||
return (result);
|
return (result);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static isc_result_t
|
||||||
|
configure_view_nametable(const cfg_obj_t *vconfig, const cfg_obj_t *config,
|
||||||
|
const char *confname, const char *conftuplename,
|
||||||
|
isc_mem_t *mctx, dns_rbt_t **rbtp)
|
||||||
|
{
|
||||||
|
isc_result_t result;
|
||||||
|
const cfg_obj_t *maps[3];
|
||||||
|
const cfg_obj_t *obj = NULL;
|
||||||
|
const cfg_listelt_t *element;
|
||||||
|
int i = 0;
|
||||||
|
dns_fixedname_t fixed;
|
||||||
|
dns_name_t *name;
|
||||||
|
isc_buffer_t b;
|
||||||
|
const char *str;
|
||||||
|
const cfg_obj_t *nameobj;
|
||||||
|
|
||||||
|
if (*rbtp != NULL)
|
||||||
|
dns_rbt_destroy(rbtp);
|
||||||
|
if (vconfig != NULL)
|
||||||
|
maps[i++] = cfg_tuple_get(vconfig, "options");
|
||||||
|
if (config != NULL) {
|
||||||
|
const cfg_obj_t *options = NULL;
|
||||||
|
(void)cfg_map_get(config, "options", &options);
|
||||||
|
if (options != NULL)
|
||||||
|
maps[i++] = options;
|
||||||
|
}
|
||||||
|
maps[i] = NULL;
|
||||||
|
|
||||||
|
(void)ns_config_get(maps, confname, &obj);
|
||||||
|
if (obj == NULL)
|
||||||
|
/*
|
||||||
|
* No value available. *rbtp == NULL.
|
||||||
|
*/
|
||||||
|
return (ISC_R_SUCCESS);
|
||||||
|
|
||||||
|
if (conftuplename != NULL) {
|
||||||
|
obj = cfg_tuple_get(obj, conftuplename);
|
||||||
|
if (cfg_obj_isvoid(obj))
|
||||||
|
return (ISC_R_SUCCESS);
|
||||||
|
}
|
||||||
|
|
||||||
|
result = dns_rbt_create(mctx, NULL, NULL, rbtp);
|
||||||
|
if (result != ISC_R_SUCCESS)
|
||||||
|
return (result);
|
||||||
|
|
||||||
|
dns_fixedname_init(&fixed);
|
||||||
|
name = dns_fixedname_name(&fixed);
|
||||||
|
for (element = cfg_list_first(obj);
|
||||||
|
element != NULL;
|
||||||
|
element = cfg_list_next(element)) {
|
||||||
|
nameobj = cfg_listelt_value(element);
|
||||||
|
str = cfg_obj_asstring(nameobj);
|
||||||
|
isc_buffer_init(&b, str, strlen(str));
|
||||||
|
isc_buffer_add(&b, strlen(str));
|
||||||
|
CHECK(dns_name_fromtext(name, &b, dns_rootname,
|
||||||
|
ISC_FALSE, NULL));
|
||||||
|
/*
|
||||||
|
* We don't need the node data, but need to set dummy data to
|
||||||
|
* avoid a partial match with an empty node. For example, if
|
||||||
|
* we have foo.example.com and bar.example.com, we'd get a match
|
||||||
|
* for baz.example.com, which is not the expected result.
|
||||||
|
* We simply use (void *)1 as the dummy data.
|
||||||
|
*/
|
||||||
|
CHECK(dns_rbt_addname(*rbtp, name, (void *)1));
|
||||||
|
}
|
||||||
|
|
||||||
|
return (result);
|
||||||
|
|
||||||
|
cleanup:
|
||||||
|
dns_rbt_destroy(rbtp);
|
||||||
|
return (result);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
static isc_result_t
|
static isc_result_t
|
||||||
configure_view_dnsseckey(const cfg_obj_t *vconfig, const cfg_obj_t *key,
|
configure_view_dnsseckey(const cfg_obj_t *vconfig, const cfg_obj_t *key,
|
||||||
dns_keytable_t *keytable, isc_mem_t *mctx)
|
dns_keytable_t *keytable, isc_mem_t *mctx)
|
||||||
@@ -1722,10 +1804,10 @@ configure_view(dns_view_t *view, const cfg_obj_t *config,
|
|||||||
/*
|
/*
|
||||||
* Configure the "match-clients" and "match-destinations" ACL.
|
* Configure the "match-clients" and "match-destinations" ACL.
|
||||||
*/
|
*/
|
||||||
CHECK(configure_view_acl(vconfig, config, "match-clients", actx,
|
CHECK(configure_view_acl(vconfig, config, "match-clients", NULL, actx,
|
||||||
ns_g_mctx, &view->matchclients));
|
ns_g_mctx, &view->matchclients));
|
||||||
CHECK(configure_view_acl(vconfig, config, "match-destinations", actx,
|
CHECK(configure_view_acl(vconfig, config, "match-destinations", NULL,
|
||||||
ns_g_mctx, &view->matchdestinations));
|
actx, ns_g_mctx, &view->matchdestinations));
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Configure the "match-recursive-only" option.
|
* Configure the "match-recursive-only" option.
|
||||||
@@ -1797,20 +1879,20 @@ configure_view(dns_view_t *view, const cfg_obj_t *config,
|
|||||||
* "allow-recursion", and "allow-recursion-on" acls if
|
* "allow-recursion", and "allow-recursion-on" acls if
|
||||||
* configured in named.conf.
|
* configured in named.conf.
|
||||||
*/
|
*/
|
||||||
CHECK(configure_view_acl(vconfig, config, "allow-query-cache",
|
CHECK(configure_view_acl(vconfig, config, "allow-query-cache", NULL,
|
||||||
actx, ns_g_mctx, &view->queryacl));
|
actx, ns_g_mctx, &view->queryacl));
|
||||||
CHECK(configure_view_acl(vconfig, config, "allow-query-cache-on",
|
CHECK(configure_view_acl(vconfig, config, "allow-query-cache-on", NULL,
|
||||||
actx, ns_g_mctx, &view->queryonacl));
|
actx, ns_g_mctx, &view->queryonacl));
|
||||||
if (view->queryonacl == NULL)
|
if (view->queryonacl == NULL)
|
||||||
CHECK(configure_view_acl(NULL, ns_g_config,
|
CHECK(configure_view_acl(NULL, ns_g_config,
|
||||||
"allow-query-cache-on", actx,
|
"allow-query-cache-on", NULL, actx,
|
||||||
ns_g_mctx, &view->queryonacl));
|
ns_g_mctx, &view->queryonacl));
|
||||||
if (strcmp(view->name, "_bind") != 0) {
|
if (strcmp(view->name, "_bind") != 0) {
|
||||||
CHECK(configure_view_acl(vconfig, config, "allow-recursion",
|
CHECK(configure_view_acl(vconfig, config, "allow-recursion",
|
||||||
actx, ns_g_mctx,
|
NULL, actx, ns_g_mctx,
|
||||||
&view->recursionacl));
|
&view->recursionacl));
|
||||||
CHECK(configure_view_acl(vconfig, config, "allow-recursion-on",
|
CHECK(configure_view_acl(vconfig, config, "allow-recursion-on",
|
||||||
actx, ns_g_mctx,
|
NULL, actx, ns_g_mctx,
|
||||||
&view->recursiononacl));
|
&view->recursiononacl));
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1823,7 +1905,7 @@ configure_view(dns_view_t *view, const cfg_obj_t *config,
|
|||||||
if (view->queryacl == NULL && view->recursionacl != NULL)
|
if (view->queryacl == NULL && view->recursionacl != NULL)
|
||||||
dns_acl_attach(view->recursionacl, &view->queryacl);
|
dns_acl_attach(view->recursionacl, &view->queryacl);
|
||||||
if (view->queryacl == NULL && view->recursion)
|
if (view->queryacl == NULL && view->recursion)
|
||||||
CHECK(configure_view_acl(vconfig, config, "allow-query",
|
CHECK(configure_view_acl(vconfig, config, "allow-query", NULL,
|
||||||
actx, ns_g_mctx, &view->queryacl));
|
actx, ns_g_mctx, &view->queryacl));
|
||||||
if (view->recursion &&
|
if (view->recursion &&
|
||||||
view->recursionacl == NULL && view->queryacl != NULL)
|
view->recursionacl == NULL && view->queryacl != NULL)
|
||||||
@@ -1835,19 +1917,20 @@ configure_view(dns_view_t *view, const cfg_obj_t *config,
|
|||||||
*/
|
*/
|
||||||
if (view->recursionacl == NULL && view->recursion)
|
if (view->recursionacl == NULL && view->recursion)
|
||||||
CHECK(configure_view_acl(NULL, ns_g_config,
|
CHECK(configure_view_acl(NULL, ns_g_config,
|
||||||
"allow-recursion",
|
"allow-recursion", NULL,
|
||||||
actx, ns_g_mctx,
|
actx, ns_g_mctx,
|
||||||
&view->recursionacl));
|
&view->recursionacl));
|
||||||
if (view->recursiononacl == NULL && view->recursion)
|
if (view->recursiononacl == NULL && view->recursion)
|
||||||
CHECK(configure_view_acl(NULL, ns_g_config,
|
CHECK(configure_view_acl(NULL, ns_g_config,
|
||||||
"allow-recursion-on",
|
"allow-recursion-on", NULL,
|
||||||
actx, ns_g_mctx,
|
actx, ns_g_mctx,
|
||||||
&view->recursiononacl));
|
&view->recursiononacl));
|
||||||
if (view->queryacl == NULL) {
|
if (view->queryacl == NULL) {
|
||||||
if (view->recursion)
|
if (view->recursion)
|
||||||
CHECK(configure_view_acl(NULL, ns_g_config,
|
CHECK(configure_view_acl(NULL, ns_g_config,
|
||||||
"allow-query-cache", actx,
|
"allow-query-cache", NULL,
|
||||||
ns_g_mctx, &view->queryacl));
|
actx, ns_g_mctx,
|
||||||
|
&view->queryacl));
|
||||||
else {
|
else {
|
||||||
if (view->queryacl != NULL)
|
if (view->queryacl != NULL)
|
||||||
dns_acl_detach(&view->queryacl);
|
dns_acl_detach(&view->queryacl);
|
||||||
@@ -1855,6 +1938,25 @@ configure_view(dns_view_t *view, const cfg_obj_t *config,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Filter setting on addresses in the answer section.
|
||||||
|
*/
|
||||||
|
CHECK(configure_view_acl(vconfig, config, "deny-answer-addresses",
|
||||||
|
"acl", actx, ns_g_mctx, &view->denyansweracl));
|
||||||
|
CHECK(configure_view_nametable(vconfig, config, "deny-answer-addresses",
|
||||||
|
"except-from", ns_g_mctx,
|
||||||
|
&view->answeracl_exclude));
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Filter setting on names (CNAME/DNAME targets) in the answer section.
|
||||||
|
*/
|
||||||
|
CHECK(configure_view_nametable(vconfig, config, "deny-answer-aliases",
|
||||||
|
"name", ns_g_mctx,
|
||||||
|
&view->denyanswernames));
|
||||||
|
CHECK(configure_view_nametable(vconfig, config, "deny-answer-aliases",
|
||||||
|
"except-from", ns_g_mctx,
|
||||||
|
&view->answernames_exclude));
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Configure sortlist, if set
|
* Configure sortlist, if set
|
||||||
*/
|
*/
|
||||||
@@ -1868,19 +1970,19 @@ configure_view(dns_view_t *view, const cfg_obj_t *config,
|
|||||||
*/
|
*/
|
||||||
if (view->notifyacl == NULL)
|
if (view->notifyacl == NULL)
|
||||||
CHECK(configure_view_acl(NULL, ns_g_config,
|
CHECK(configure_view_acl(NULL, ns_g_config,
|
||||||
"allow-notify", actx,
|
"allow-notify", NULL, actx,
|
||||||
ns_g_mctx, &view->notifyacl));
|
ns_g_mctx, &view->notifyacl));
|
||||||
if (view->transferacl == NULL)
|
if (view->transferacl == NULL)
|
||||||
CHECK(configure_view_acl(NULL, ns_g_config,
|
CHECK(configure_view_acl(NULL, ns_g_config,
|
||||||
"allow-transfer", actx,
|
"allow-transfer", NULL, actx,
|
||||||
ns_g_mctx, &view->transferacl));
|
ns_g_mctx, &view->transferacl));
|
||||||
if (view->updateacl == NULL)
|
if (view->updateacl == NULL)
|
||||||
CHECK(configure_view_acl(NULL, ns_g_config,
|
CHECK(configure_view_acl(NULL, ns_g_config,
|
||||||
"allow-update", actx,
|
"allow-update", NULL, actx,
|
||||||
ns_g_mctx, &view->updateacl));
|
ns_g_mctx, &view->updateacl));
|
||||||
if (view->upfwdacl == NULL)
|
if (view->upfwdacl == NULL)
|
||||||
CHECK(configure_view_acl(NULL, ns_g_config,
|
CHECK(configure_view_acl(NULL, ns_g_config,
|
||||||
"allow-update-forwarding", actx,
|
"allow-update-forwarding", NULL, actx,
|
||||||
ns_g_mctx, &view->upfwdacl));
|
ns_g_mctx, &view->upfwdacl));
|
||||||
|
|
||||||
obj = NULL;
|
obj = NULL;
|
||||||
@@ -3301,7 +3403,7 @@ load_configuration(const char *filename, ns_server_t *server,
|
|||||||
else
|
else
|
||||||
isc_quota_soft(&server->recursionquota, 0);
|
isc_quota_soft(&server->recursionquota, 0);
|
||||||
|
|
||||||
CHECK(configure_view_acl(NULL, config, "blackhole", &aclconfctx,
|
CHECK(configure_view_acl(NULL, config, "blackhole", NULL, &aclconfctx,
|
||||||
ns_g_mctx, &server->blackholeacl));
|
ns_g_mctx, &server->blackholeacl));
|
||||||
if (server->blackholeacl != NULL)
|
if (server->blackholeacl != NULL)
|
||||||
dns_dispatchmgr_setblackhole(ns_g_dispatchmgr,
|
dns_dispatchmgr_setblackhole(ns_g_dispatchmgr,
|
||||||
|
@@ -15,7 +15,7 @@
|
|||||||
# OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
|
# OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
|
||||||
# PERFORMANCE OF THIS SOFTWARE.
|
# PERFORMANCE OF THIS SOFTWARE.
|
||||||
|
|
||||||
# $Id: ans.pl,v 1.10 2007/09/24 04:13:25 marka Exp $
|
# $Id: ans.pl,v 1.11 2009/05/29 22:22:36 jinmei Exp $
|
||||||
|
|
||||||
#
|
#
|
||||||
# Ad hoc name server
|
# Ad hoc name server
|
||||||
@@ -52,6 +52,7 @@ for (;;) {
|
|||||||
|
|
||||||
my @questions = $packet->question;
|
my @questions = $packet->question;
|
||||||
my $qname = $questions[0]->qname;
|
my $qname = $questions[0]->qname;
|
||||||
|
my $qtype = $questions[0]->qtype;
|
||||||
|
|
||||||
if ($qname eq "cname1.example.com") {
|
if ($qname eq "cname1.example.com") {
|
||||||
# Data for the "cname + other data / 1" test
|
# Data for the "cname + other data / 1" test
|
||||||
@@ -61,6 +62,32 @@ for (;;) {
|
|||||||
# Data for the "cname + other data / 2" test: same RRs in opposite order
|
# Data for the "cname + other data / 2" test: same RRs in opposite order
|
||||||
$packet->push("answer", new Net::DNS::RR("cname2.example.com 300 A 1.2.3.4"));
|
$packet->push("answer", new Net::DNS::RR("cname2.example.com 300 A 1.2.3.4"));
|
||||||
$packet->push("answer", new Net::DNS::RR("cname2.example.com 300 CNAME cname2.example.com"));
|
$packet->push("answer", new Net::DNS::RR("cname2.example.com 300 CNAME cname2.example.com"));
|
||||||
|
} elsif ($qname eq "www.example.org" || $qname eq "www.example.net" ||
|
||||||
|
$qname eq "badcname.example.org" ||
|
||||||
|
$qname eq "goodcname.example.org" ||
|
||||||
|
$qname eq "foo.baddname.example.org" ||
|
||||||
|
$qname eq "foo.gooddname.example.org") {
|
||||||
|
# Data for address/alias filtering.
|
||||||
|
if ($qtype eq "A") {
|
||||||
|
$packet->push("answer",
|
||||||
|
new Net::DNS::RR($qname .
|
||||||
|
" 300 A 192.0.2.1"));
|
||||||
|
} elsif ($qtype eq "AAAA") {
|
||||||
|
$packet->push("answer",
|
||||||
|
new Net::DNS::RR($qname .
|
||||||
|
" 300 AAAA 2001:db8:beef::1"));
|
||||||
|
}
|
||||||
|
} elsif ($qname eq "badcname.example.net" ||
|
||||||
|
$qname eq "goodcname.example.net") {
|
||||||
|
# Data for CNAME/DNAME filtering. We need to make one-level
|
||||||
|
# delegation to avoid automatic acceptance for subdomain aliases
|
||||||
|
$packet->push("authority", new Net::DNS::RR("example.net 300 NS ns.example.net"));
|
||||||
|
$packet->push("additional", new Net::DNS::RR("ns.example.net 300 A 10.53.0.3"));
|
||||||
|
} elsif ($qname =~ /sub\.example\.org/) {
|
||||||
|
# Data for CNAME/DNAME filtering. The final answers are
|
||||||
|
# expected to be accepted regardless of the filter setting.
|
||||||
|
$packet->push("authority", new Net::DNS::RR("sub.example.org 300 NS ns.sub.example.org"));
|
||||||
|
$packet->push("additional", new Net::DNS::RR("ns.sub.example.org 300 A 10.53.0.3"));
|
||||||
} else {
|
} else {
|
||||||
# Data for the "bogus referrals" test
|
# Data for the "bogus referrals" test
|
||||||
$packet->push("authority", new Net::DNS::RR("below.www.example.com 300 NS ns.below.www.example.com"));
|
$packet->push("authority", new Net::DNS::RR("below.www.example.com 300 NS ns.below.www.example.com"));
|
||||||
|
@@ -15,7 +15,7 @@
|
|||||||
# OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
|
# OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
|
||||||
# PERFORMANCE OF THIS SOFTWARE.
|
# PERFORMANCE OF THIS SOFTWARE.
|
||||||
|
|
||||||
# $Id: ans.pl,v 1.9 2007/09/24 04:13:25 marka Exp $
|
# $Id: ans.pl,v 1.10 2009/05/29 22:22:36 jinmei Exp $
|
||||||
|
|
||||||
#
|
#
|
||||||
# Ad hoc name server
|
# Ad hoc name server
|
||||||
@@ -50,7 +50,42 @@ for (;;) {
|
|||||||
|
|
||||||
$packet->header->qr(1);
|
$packet->header->qr(1);
|
||||||
|
|
||||||
|
my @questions = $packet->question;
|
||||||
|
my $qname = $questions[0]->qname;
|
||||||
|
|
||||||
|
if ($qname eq "badcname.example.net") {
|
||||||
|
$packet->push("answer",
|
||||||
|
new Net::DNS::RR($qname .
|
||||||
|
" 300 CNAME badcname.example.org"));
|
||||||
|
} elsif ($qname eq "foo.baddname.example.net") {
|
||||||
|
$packet->push("answer",
|
||||||
|
new Net::DNS::RR("baddname.example.net" .
|
||||||
|
" 300 DNAME baddname.example.org"));
|
||||||
|
} elsif ($qname eq "foo.gooddname.example.net") {
|
||||||
|
$packet->push("answer",
|
||||||
|
new Net::DNS::RR("gooddname.example.net" .
|
||||||
|
" 300 DNAME gooddname.example.org"));
|
||||||
|
} elsif ($qname eq "goodcname.example.net") {
|
||||||
|
$packet->push("answer",
|
||||||
|
new Net::DNS::RR($qname .
|
||||||
|
" 300 CNAME goodcname.example.org"));
|
||||||
|
} elsif ($qname eq "cname.sub.example.org") {
|
||||||
|
$packet->push("answer",
|
||||||
|
new Net::DNS::RR($qname .
|
||||||
|
" 300 CNAME ok.sub.example.org"));
|
||||||
|
} elsif ($qname eq "ok.sub.example.org") {
|
||||||
|
$packet->push("answer",
|
||||||
|
new Net::DNS::RR($qname . " 300 A 192.0.2.1"));
|
||||||
|
} elsif ($qname eq "www.dname.sub.example.org") {
|
||||||
|
$packet->push("answer",
|
||||||
|
new Net::DNS::RR("dname.sub.example.org" .
|
||||||
|
" 300 DNAME ok.sub.example.org"));
|
||||||
|
} elsif ($qname eq "www.ok.sub.example.org") {
|
||||||
|
$packet->push("answer",
|
||||||
|
new Net::DNS::RR($qname . " 300 A 192.0.2.1"));
|
||||||
|
} else {
|
||||||
$packet->push("answer", new Net::DNS::RR("www.example.com 300 A 1.2.3.4"));
|
$packet->push("answer", new Net::DNS::RR("www.example.com 300 A 1.2.3.4"));
|
||||||
|
}
|
||||||
|
|
||||||
$sock->send($packet->data);
|
$sock->send($packet->data);
|
||||||
|
|
||||||
|
@@ -14,9 +14,10 @@
|
|||||||
# OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
|
# OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
|
||||||
# PERFORMANCE OF THIS SOFTWARE.
|
# PERFORMANCE OF THIS SOFTWARE.
|
||||||
|
|
||||||
# $Id: clean.sh,v 1.1 2008/07/17 01:15:34 marka Exp $
|
# $Id: clean.sh,v 1.2 2009/05/29 22:22:36 jinmei Exp $
|
||||||
|
|
||||||
#
|
#
|
||||||
# Clean up after resolver tests.
|
# Clean up after resolver tests.
|
||||||
#
|
#
|
||||||
rm -f */named.memstats
|
rm -f */named.memstats
|
||||||
|
rm -f dig.out
|
||||||
|
@@ -15,7 +15,7 @@
|
|||||||
* PERFORMANCE OF THIS SOFTWARE.
|
* PERFORMANCE OF THIS SOFTWARE.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/* $Id: named.conf,v 1.13 2007/06/18 23:47:30 tbox Exp $ */
|
/* $Id: named.conf,v 1.14 2009/05/29 22:22:36 jinmei Exp $ */
|
||||||
|
|
||||||
controls { /* empty */ };
|
controls { /* empty */ };
|
||||||
|
|
||||||
@@ -29,6 +29,11 @@ options {
|
|||||||
listen-on-v6 { none; };
|
listen-on-v6 { none; };
|
||||||
recursion yes;
|
recursion yes;
|
||||||
acache-enable yes;
|
acache-enable yes;
|
||||||
|
deny-answer-addresses { 192.0.2.0/24; 2001:db8:beef::/48; }
|
||||||
|
except-from { "example.org"; };
|
||||||
|
deny-answer-aliases { "example.org"; }
|
||||||
|
except-from { "goodcname.example.net";
|
||||||
|
"gooddname.example.net"; };
|
||||||
};
|
};
|
||||||
|
|
||||||
zone "." {
|
zone "." {
|
||||||
|
@@ -15,7 +15,7 @@
|
|||||||
# OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
|
# OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
|
||||||
# PERFORMANCE OF THIS SOFTWARE.
|
# PERFORMANCE OF THIS SOFTWARE.
|
||||||
|
|
||||||
# $Id: tests.sh,v 1.9 2007/06/19 23:47:05 tbox Exp $
|
# $Id: tests.sh,v 1.10 2009/05/29 22:22:36 jinmei Exp $
|
||||||
|
|
||||||
SYSTEMTESTTOP=..
|
SYSTEMTESTTOP=..
|
||||||
. $SYSTEMTESTTOP/conf.sh
|
. $SYSTEMTESTTOP/conf.sh
|
||||||
@@ -35,5 +35,75 @@ $DIG +tcp cname2.example.com. a @10.53.0.1 -p 5300 >/dev/null || status=1
|
|||||||
echo "I:check that server is still running"
|
echo "I:check that server is still running"
|
||||||
$DIG +tcp www.example.com. a @10.53.0.1 -p 5300 >/dev/null || status=1
|
$DIG +tcp www.example.com. a @10.53.0.1 -p 5300 >/dev/null || status=1
|
||||||
|
|
||||||
|
echo "I:checking answer IPv4 address filtering (deny)"
|
||||||
|
ret=0
|
||||||
|
$DIG +tcp www.example.net @10.53.0.1 a -p 5300 > dig.out || ret=1
|
||||||
|
grep "status: SERVFAIL" dig.out > /dev/null || ret=1
|
||||||
|
if [ $ret != 0 ]; then echo "I:failed"; fi
|
||||||
|
status=`expr $status + $ret`
|
||||||
|
|
||||||
|
echo "I:checking answer IPv6 address filtering (deny)"
|
||||||
|
ret=0
|
||||||
|
$DIG +tcp www.example.net @10.53.0.1 aaaa -p 5300 > dig.out || ret=1
|
||||||
|
grep "status: SERVFAIL" dig.out > /dev/null || ret=1
|
||||||
|
if [ $ret != 0 ]; then echo "I:failed"; fi
|
||||||
|
status=`expr $status + $ret`
|
||||||
|
|
||||||
|
echo "I:checking answer IPv4 address filtering (accept)"
|
||||||
|
ret=0
|
||||||
|
$DIG +tcp www.example.org @10.53.0.1 a -p 5300 > dig.out || ret=1
|
||||||
|
grep "status: NOERROR" dig.out > /dev/null || ret=1
|
||||||
|
if [ $ret != 0 ]; then echo "I:failed"; fi
|
||||||
|
status=`expr $status + $ret`
|
||||||
|
|
||||||
|
echo "I:checking answer IPv6 address filtering (accept)"
|
||||||
|
ret=0
|
||||||
|
$DIG +tcp www.example.org @10.53.0.1 aaaa -p 5300 > dig.out || ret=1
|
||||||
|
grep "status: NOERROR" dig.out > /dev/null || ret=1
|
||||||
|
if [ $ret != 0 ]; then echo "I:failed"; fi
|
||||||
|
status=`expr $status + $ret`
|
||||||
|
|
||||||
|
echo "I:checking CNAME target filtering (deny)"
|
||||||
|
ret=0
|
||||||
|
$DIG +tcp badcname.example.net @10.53.0.1 a -p 5300 > dig.out || ret=1
|
||||||
|
grep "status: SERVFAIL" dig.out > /dev/null || ret=1
|
||||||
|
if [ $ret != 0 ]; then echo "I:failed"; fi
|
||||||
|
status=`expr $status + $ret`
|
||||||
|
|
||||||
|
echo "I:checking CNAME target filtering (accept)"
|
||||||
|
ret=0
|
||||||
|
$DIG +tcp goodcname.example.net @10.53.0.1 a -p 5300 > dig.out || ret=1
|
||||||
|
grep "status: NOERROR" dig.out > /dev/null || ret=1
|
||||||
|
if [ $ret != 0 ]; then echo "I:failed"; fi
|
||||||
|
status=`expr $status + $ret`
|
||||||
|
|
||||||
|
echo "I:checking CNAME target filtering (accept due to subdomain)"
|
||||||
|
ret=0
|
||||||
|
$DIG +tcp cname.sub.example.org @10.53.0.1 a -p 5300 > dig.out || ret=1
|
||||||
|
grep "status: NOERROR" dig.out > /dev/null || ret=1
|
||||||
|
if [ $ret != 0 ]; then echo "I:failed"; fi
|
||||||
|
status=`expr $status + $ret`
|
||||||
|
|
||||||
|
echo "I:checking DNAME target filtering (deny)"
|
||||||
|
ret=0
|
||||||
|
$DIG +tcp foo.baddname.example.net @10.53.0.1 a -p 5300 > dig.out || ret=1
|
||||||
|
grep "status: SERVFAIL" dig.out > /dev/null || ret=1
|
||||||
|
if [ $ret != 0 ]; then echo "I:failed"; fi
|
||||||
|
status=`expr $status + $ret`
|
||||||
|
|
||||||
|
echo "I:checking DNAME target filtering (accept)"
|
||||||
|
ret=0
|
||||||
|
$DIG +tcp foo.gooddname.example.net @10.53.0.1 a -p 5300 > dig.out || ret=1
|
||||||
|
grep "status: NOERROR" dig.out > /dev/null || ret=1
|
||||||
|
if [ $ret != 0 ]; then echo "I:failed"; fi
|
||||||
|
status=`expr $status + $ret`
|
||||||
|
|
||||||
|
echo "I:checking DNAME target filtering (accept due to subdomain)"
|
||||||
|
ret=0
|
||||||
|
$DIG +tcp www.dname.sub.example.org @10.53.0.1 a -p 5300 > dig.out || ret=1
|
||||||
|
grep "status: NOERROR" dig.out > /dev/null || ret=1
|
||||||
|
if [ $ret != 0 ]; then echo "I:failed"; fi
|
||||||
|
status=`expr $status + $ret`
|
||||||
|
|
||||||
echo "I:exit status: $status"
|
echo "I:exit status: $status"
|
||||||
exit $status
|
exit $status
|
||||||
|
@@ -18,7 +18,7 @@
|
|||||||
- PERFORMANCE OF THIS SOFTWARE.
|
- PERFORMANCE OF THIS SOFTWARE.
|
||||||
-->
|
-->
|
||||||
|
|
||||||
<!-- File: $Id: Bv9ARM-book.xml,v 1.409 2009/05/14 20:46:04 jreed Exp $ -->
|
<!-- File: $Id: Bv9ARM-book.xml,v 1.410 2009/05/29 22:22:36 jinmei Exp $ -->
|
||||||
<book xmlns:xi="http://www.w3.org/2001/XInclude">
|
<book xmlns:xi="http://www.w3.org/2001/XInclude">
|
||||||
<title>BIND 9 Administrator Reference Manual</title>
|
<title>BIND 9 Administrator Reference Manual</title>
|
||||||
|
|
||||||
@@ -2861,6 +2861,19 @@ $ORIGIN 0.0.0.0.0.0.0.0.8.b.d.0.1.0.0.2.ip6.arpa.
|
|||||||
</para>
|
</para>
|
||||||
</entry>
|
</entry>
|
||||||
</row>
|
</row>
|
||||||
|
<row rowsep="0">
|
||||||
|
<entry colname="1">
|
||||||
|
<para>
|
||||||
|
<varname>namelist</varname>
|
||||||
|
</para>
|
||||||
|
</entry>
|
||||||
|
<entry colname="2">
|
||||||
|
<para>
|
||||||
|
A list of one or more <varname>domain_name</varname>
|
||||||
|
elements.
|
||||||
|
</para>
|
||||||
|
</entry>
|
||||||
|
</row>
|
||||||
<row rowsep="0">
|
<row rowsep="0">
|
||||||
<entry colname="1">
|
<entry colname="1">
|
||||||
<para>
|
<para>
|
||||||
@@ -4951,6 +4964,8 @@ badresp:1,adberr:0,findfail:0,valfail:0]
|
|||||||
<optional> disable-empty-zone <replaceable>zone_name</replaceable> ; </optional>
|
<optional> disable-empty-zone <replaceable>zone_name</replaceable> ; </optional>
|
||||||
<optional> zero-no-soa-ttl <replaceable>yes_or_no</replaceable> ; </optional>
|
<optional> zero-no-soa-ttl <replaceable>yes_or_no</replaceable> ; </optional>
|
||||||
<optional> zero-no-soa-ttl-cache <replaceable>yes_or_no</replaceable> ; </optional>
|
<optional> zero-no-soa-ttl-cache <replaceable>yes_or_no</replaceable> ; </optional>
|
||||||
|
<optional> deny-answer-addresses { <replaceable>address_match_list</replaceable> } <optional> except-from { <replaceable>namelist</replaceable> } </optional>;</optional>
|
||||||
|
<optional> deny-answer-aliases { <replaceable>namelist</replaceable> } <optional> except-from { <replaceable>namelist</replaceable> } </optional>;</optional>
|
||||||
};
|
};
|
||||||
</programlisting>
|
</programlisting>
|
||||||
|
|
||||||
@@ -8426,6 +8441,142 @@ XXX: end of RFC1918 addresses #defined out -->
|
|||||||
|
|
||||||
</sect3>
|
</sect3>
|
||||||
|
|
||||||
|
<sect3>
|
||||||
|
<title>Content Filtering</title>
|
||||||
|
<para>
|
||||||
|
<acronym>BIND</acronym> 9 provides the ability to filter
|
||||||
|
out DNS responses from external DNS servers containing
|
||||||
|
certain types of data in the answer section.
|
||||||
|
Specifically, it can reject address (A or AAAA) records if
|
||||||
|
the corresponding IPv4 or IPv6 addresses match the given
|
||||||
|
<varname>address_match_list</varname> of the
|
||||||
|
<command>deny-answer-addresses</command> option.
|
||||||
|
It can also reject CNAME or DNAME records if the "alias"
|
||||||
|
name (i.e., the CNAME alias or the substituted query name
|
||||||
|
due to DNAME) matches the
|
||||||
|
given <varname>namelist</varname> of the
|
||||||
|
<command>deny-answer-aliases</command> option, where
|
||||||
|
"match" means the alias name is a subdomain of one of
|
||||||
|
the <varname>name_list</varname> elements.
|
||||||
|
If the optional <varname>namelist</varname> is specified
|
||||||
|
with <command>except-from</command>, records whose query name
|
||||||
|
matches the list will be accepted regardless of the filter
|
||||||
|
setting.
|
||||||
|
Likewise, if the alias name is a subdomain of the
|
||||||
|
corresponding zone, the <command>deny-answer-aliases</command>
|
||||||
|
filter will not apply;
|
||||||
|
for example, even if "example.com" is specified for
|
||||||
|
<command>deny-answer-aliases</command>,
|
||||||
|
</para>
|
||||||
|
<programlisting>www.example.com. CNAME xxx.example.com.</programlisting>
|
||||||
|
|
||||||
|
<para>
|
||||||
|
returned by an "example.com" server will be accepted.
|
||||||
|
</para>
|
||||||
|
|
||||||
|
<para>
|
||||||
|
In the <varname>address_match_list</varname> of the
|
||||||
|
<command>deny-answer-addresses</command> option, only
|
||||||
|
<varname>ip_addr</varname>
|
||||||
|
and <varname>ip_prefix</varname>
|
||||||
|
are meaningful;
|
||||||
|
any <varname>key_id</varname> will be silently ignored.
|
||||||
|
</para>
|
||||||
|
|
||||||
|
<para>
|
||||||
|
If a response message is rejected due to the filtering,
|
||||||
|
the entire message is discarded without being cached, and
|
||||||
|
a SERVFAIL error will be returned to the client.
|
||||||
|
</para>
|
||||||
|
|
||||||
|
<para>
|
||||||
|
This filtering is intended to prevent "DNS rebinding attacks," in
|
||||||
|
which an attacker, in response to a query for a domain name the
|
||||||
|
attacker controls, returns an IP address within your own network or
|
||||||
|
an alias name within your own domain.
|
||||||
|
A naive web browser or script could then serve as an
|
||||||
|
unintended proxy, allowing the attacker
|
||||||
|
to get access to an internal node of your local network
|
||||||
|
that couldn't be externally accessed otherwise.
|
||||||
|
See the paper available at
|
||||||
|
<ulink>
|
||||||
|
http://portal.acm.org/citation.cfm?id=1315245.1315298
|
||||||
|
</ulink>
|
||||||
|
for more details about the attacks.
|
||||||
|
</para>
|
||||||
|
|
||||||
|
<para>
|
||||||
|
For example, if you own a domain named "example.net" and
|
||||||
|
your internal network uses an IPv4 prefix 192.0.2.0/24,
|
||||||
|
you might specify the following rules:
|
||||||
|
</para>
|
||||||
|
|
||||||
|
<programlisting>deny-answer-addresses { 192.0.2.0/24; } except-from { "example.net"; };
|
||||||
|
deny-answer-aliases { "example.net"; };
|
||||||
|
</programlisting>
|
||||||
|
|
||||||
|
<para>
|
||||||
|
If an external attacker lets a web browser in your local
|
||||||
|
network look up an IPv4 address of "attacker.example.com",
|
||||||
|
the attacker's DNS server would return a response like this:
|
||||||
|
</para>
|
||||||
|
|
||||||
|
<programlisting>attacker.example.com. A 192.0.2.1</programlisting>
|
||||||
|
|
||||||
|
<para>
|
||||||
|
in the answer section.
|
||||||
|
Since the rdata of this record (the IPv4 address) matches
|
||||||
|
the specified prefix 192.0.2.0/24, this response will be
|
||||||
|
ignored.
|
||||||
|
</para>
|
||||||
|
|
||||||
|
<para>
|
||||||
|
On the other hand, if the browser looks up a legitimate
|
||||||
|
internal web server "www.example.net" and the
|
||||||
|
following response is returned to
|
||||||
|
the <acronym>BIND</acronym> 9 server
|
||||||
|
</para>
|
||||||
|
|
||||||
|
<programlisting>www.example.net. A 192.0.2.2</programlisting>
|
||||||
|
|
||||||
|
<para>
|
||||||
|
it will be accepted since the owner name "www.example.net"
|
||||||
|
matches the <command>except-from</command> element,
|
||||||
|
"example.net".
|
||||||
|
</para>
|
||||||
|
|
||||||
|
<para>
|
||||||
|
Note that this is not really an attack on the DNS per se.
|
||||||
|
In fact, there is nothing wrong for an "external" name to
|
||||||
|
be mapped to your "internal" IP address or domain name
|
||||||
|
from the DNS point of view.
|
||||||
|
It might actually be provided for a legitimate purpose,
|
||||||
|
such as for debugging.
|
||||||
|
As long as the mapping is provided by the correct owner,
|
||||||
|
it is not possible or does not make sense to detect
|
||||||
|
whether the intent of the mapping is legitimate or not
|
||||||
|
within the DNS.
|
||||||
|
The "rebinding" attack must primarily be protected at the
|
||||||
|
application that uses the DNS.
|
||||||
|
For a large site, however, it may be difficult to protect
|
||||||
|
all possible applications at once.
|
||||||
|
This filtering feature is provided only to help such an
|
||||||
|
operational environment;
|
||||||
|
it is generally discouraged to turn it on unless you are
|
||||||
|
very sure you have no other choice and the attack is a
|
||||||
|
real threat for your applications.
|
||||||
|
</para>
|
||||||
|
|
||||||
|
<para>
|
||||||
|
Care should be particularly taken if you want to use this
|
||||||
|
option for addresses within 127.0.0.0/8.
|
||||||
|
These addresses are obviously "internal", but many
|
||||||
|
applications conventionally rely on a DNS mapping from
|
||||||
|
some name to such an address.
|
||||||
|
Filtering out DNS records containing this address
|
||||||
|
spuriously can break such applications.
|
||||||
|
</para>
|
||||||
|
</sect3>
|
||||||
</sect2>
|
</sect2>
|
||||||
|
|
||||||
<sect2 id="server_statement_grammar">
|
<sect2 id="server_statement_grammar">
|
||||||
|
@@ -15,7 +15,7 @@
|
|||||||
* PERFORMANCE OF THIS SOFTWARE.
|
* PERFORMANCE OF THIS SOFTWARE.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/* $Id: view.h,v 1.116 2009/01/27 22:29:59 jinmei Exp $ */
|
/* $Id: view.h,v 1.117 2009/05/29 22:22:37 jinmei Exp $ */
|
||||||
|
|
||||||
#ifndef DNS_VIEW_H
|
#ifndef DNS_VIEW_H
|
||||||
#define DNS_VIEW_H 1
|
#define DNS_VIEW_H 1
|
||||||
@@ -128,6 +128,10 @@ struct dns_view {
|
|||||||
dns_acl_t * transferacl;
|
dns_acl_t * transferacl;
|
||||||
dns_acl_t * updateacl;
|
dns_acl_t * updateacl;
|
||||||
dns_acl_t * upfwdacl;
|
dns_acl_t * upfwdacl;
|
||||||
|
dns_acl_t * denyansweracl;
|
||||||
|
dns_rbt_t * answeracl_exclude;
|
||||||
|
dns_rbt_t * denyanswernames;
|
||||||
|
dns_rbt_t * answernames_exclude;
|
||||||
isc_boolean_t requestixfr;
|
isc_boolean_t requestixfr;
|
||||||
isc_boolean_t provideixfr;
|
isc_boolean_t provideixfr;
|
||||||
isc_boolean_t requestnsid;
|
isc_boolean_t requestnsid;
|
||||||
|
@@ -15,7 +15,7 @@
|
|||||||
* PERFORMANCE OF THIS SOFTWARE.
|
* PERFORMANCE OF THIS SOFTWARE.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/* $Id: resolver.c,v 1.398 2009/05/11 02:38:35 tbox Exp $ */
|
/* $Id: resolver.c,v 1.399 2009/05/29 22:22:36 jinmei Exp $ */
|
||||||
|
|
||||||
/*! \file */
|
/*! \file */
|
||||||
|
|
||||||
@@ -4837,6 +4837,134 @@ dname_target(dns_rdataset_t *rdataset, dns_name_t *qname, dns_name_t *oname,
|
|||||||
return (result);
|
return (result);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static isc_boolean_t
|
||||||
|
is_answeraddress_allowed(dns_view_t *view, dns_name_t *name,
|
||||||
|
dns_rdataset_t *rdataset)
|
||||||
|
{
|
||||||
|
isc_result_t result;
|
||||||
|
dns_rdata_t rdata = DNS_RDATA_INIT;
|
||||||
|
struct in_addr ina;
|
||||||
|
struct in6_addr in6a;
|
||||||
|
isc_netaddr_t netaddr;
|
||||||
|
char addrbuf[ISC_NETADDR_FORMATSIZE];
|
||||||
|
char namebuf[DNS_NAME_FORMATSIZE];
|
||||||
|
char classbuf[64];
|
||||||
|
char typebuf[64];
|
||||||
|
int match;
|
||||||
|
|
||||||
|
/* By default, we allow any addresses. */
|
||||||
|
if (view->denyansweracl == NULL)
|
||||||
|
return (ISC_TRUE);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* If the owner name matches one in the exclusion list, either exactly
|
||||||
|
* or partially, allow it.
|
||||||
|
*/
|
||||||
|
if (view->answeracl_exclude != NULL) {
|
||||||
|
dns_rbtnode_t *node = NULL;
|
||||||
|
|
||||||
|
result = dns_rbt_findnode(view->answeracl_exclude, name, NULL,
|
||||||
|
&node, NULL, 0, NULL, NULL);
|
||||||
|
|
||||||
|
if (result == ISC_R_SUCCESS || result == DNS_R_PARTIALMATCH)
|
||||||
|
return (ISC_TRUE);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Otherwise, search the filter list for a match for each address
|
||||||
|
* record. If a match is found, the address should be filtered,
|
||||||
|
* so should the entire answer.
|
||||||
|
*/
|
||||||
|
for (result = dns_rdataset_first(rdataset);
|
||||||
|
result == ISC_R_SUCCESS;
|
||||||
|
result = dns_rdataset_next(rdataset)) {
|
||||||
|
dns_rdata_reset(&rdata);
|
||||||
|
dns_rdataset_current(rdataset, &rdata);
|
||||||
|
if (rdataset->type == dns_rdatatype_a) {
|
||||||
|
INSIST(rdata.length == sizeof(ina.s_addr));
|
||||||
|
memcpy(&ina.s_addr, rdata.data, sizeof(ina.s_addr));
|
||||||
|
isc_netaddr_fromin(&netaddr, &ina);
|
||||||
|
} else {
|
||||||
|
INSIST(rdata.length == sizeof(in6a.s6_addr));
|
||||||
|
memcpy(in6a.s6_addr, rdata.data, sizeof(in6a.s6_addr));
|
||||||
|
isc_netaddr_fromin6(&netaddr, &in6a);
|
||||||
|
}
|
||||||
|
|
||||||
|
result = dns_acl_match(&netaddr, NULL, view->denyansweracl,
|
||||||
|
&view->aclenv, &match, NULL);
|
||||||
|
|
||||||
|
if (result == ISC_R_SUCCESS && match > 0) {
|
||||||
|
isc_netaddr_format(&netaddr, addrbuf, sizeof(addrbuf));
|
||||||
|
dns_name_format(name, namebuf, sizeof(namebuf));
|
||||||
|
dns_rdatatype_format(rdataset->type, typebuf,
|
||||||
|
sizeof(typebuf));
|
||||||
|
dns_rdataclass_format(rdataset->rdclass, classbuf,
|
||||||
|
sizeof(classbuf));
|
||||||
|
isc_log_write(dns_lctx, DNS_LOGCATEGORY_RESOLVER,
|
||||||
|
DNS_LOGMODULE_RESOLVER, ISC_LOG_NOTICE,
|
||||||
|
"answer address %s denied for %s/%s/%s",
|
||||||
|
addrbuf, namebuf, typebuf, classbuf);
|
||||||
|
return (ISC_FALSE);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return (ISC_TRUE);
|
||||||
|
}
|
||||||
|
|
||||||
|
static isc_boolean_t
|
||||||
|
is_answertarget_allowed(dns_view_t *view, dns_name_t *name,
|
||||||
|
dns_rdatatype_t type, dns_name_t *tname,
|
||||||
|
dns_name_t *domain)
|
||||||
|
{
|
||||||
|
isc_result_t result;
|
||||||
|
dns_rbtnode_t *node = NULL;
|
||||||
|
char qnamebuf[DNS_NAME_FORMATSIZE];
|
||||||
|
char tnamebuf[DNS_NAME_FORMATSIZE];
|
||||||
|
char classbuf[64];
|
||||||
|
char typebuf[64];
|
||||||
|
|
||||||
|
/* By default, we allow any target name. */
|
||||||
|
if (view->denyanswernames == NULL)
|
||||||
|
return (ISC_TRUE);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* If the owner name matches one in the exclusion list, either exactly
|
||||||
|
* or partially, allow it.
|
||||||
|
*/
|
||||||
|
if (view->answernames_exclude != NULL) {
|
||||||
|
result = dns_rbt_findnode(view->answernames_exclude, name, NULL,
|
||||||
|
&node, NULL, 0, NULL, NULL);
|
||||||
|
if (result == ISC_R_SUCCESS || result == DNS_R_PARTIALMATCH)
|
||||||
|
return (ISC_TRUE);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* If the target name is a subdomain of the search domain, allow it.
|
||||||
|
*/
|
||||||
|
if (dns_name_issubdomain(tname, domain))
|
||||||
|
return (ISC_TRUE);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Otherwise, apply filters.
|
||||||
|
*/
|
||||||
|
result = dns_rbt_findnode(view->denyanswernames, tname, NULL, &node,
|
||||||
|
NULL, 0, NULL, NULL);
|
||||||
|
if (result == ISC_R_SUCCESS || result == DNS_R_PARTIALMATCH) {
|
||||||
|
dns_name_format(name, qnamebuf, sizeof(qnamebuf));
|
||||||
|
dns_name_format(tname, tnamebuf, sizeof(tnamebuf));
|
||||||
|
dns_rdatatype_format(type, typebuf, sizeof(typebuf));
|
||||||
|
dns_rdataclass_format(view->rdclass, classbuf,
|
||||||
|
sizeof(classbuf));
|
||||||
|
isc_log_write(dns_lctx, DNS_LOGCATEGORY_RESOLVER,
|
||||||
|
DNS_LOGMODULE_RESOLVER, ISC_LOG_NOTICE,
|
||||||
|
"%s target %s denied for %s/%s",
|
||||||
|
typebuf, tnamebuf, qnamebuf, classbuf);
|
||||||
|
return (ISC_FALSE);
|
||||||
|
}
|
||||||
|
|
||||||
|
return (ISC_TRUE);
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Handle a no-answer response (NXDOMAIN, NXRRSET, or referral).
|
* Handle a no-answer response (NXDOMAIN, NXRRSET, or referral).
|
||||||
* If bind8_ns_resp is ISC_TRUE, this is a suspected BIND 8
|
* If bind8_ns_resp is ISC_TRUE, this is a suspected BIND 8
|
||||||
@@ -5194,6 +5322,7 @@ answer_response(fetchctx_t *fctx) {
|
|||||||
unsigned int aflag;
|
unsigned int aflag;
|
||||||
dns_rdatatype_t type;
|
dns_rdatatype_t type;
|
||||||
dns_fixedname_t dname, fqname;
|
dns_fixedname_t dname, fqname;
|
||||||
|
dns_view_t *view;
|
||||||
|
|
||||||
FCTXTRACE("answer_response");
|
FCTXTRACE("answer_response");
|
||||||
|
|
||||||
@@ -5216,6 +5345,7 @@ answer_response(fetchctx_t *fctx) {
|
|||||||
aa = ISC_FALSE;
|
aa = ISC_FALSE;
|
||||||
qname = &fctx->name;
|
qname = &fctx->name;
|
||||||
type = fctx->type;
|
type = fctx->type;
|
||||||
|
view = fctx->res->view;
|
||||||
result = dns_message_firstname(message, DNS_SECTION_ANSWER);
|
result = dns_message_firstname(message, DNS_SECTION_ANSWER);
|
||||||
while (!done && result == ISC_R_SUCCESS) {
|
while (!done && result == ISC_R_SUCCESS) {
|
||||||
name = NULL;
|
name = NULL;
|
||||||
@@ -5236,6 +5366,18 @@ answer_response(fetchctx_t *fctx) {
|
|||||||
*/
|
*/
|
||||||
return (DNS_R_FORMERR);
|
return (DNS_R_FORMERR);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Apply filters, if given, on answers to reject
|
||||||
|
* a malicious attempt of rebinding.
|
||||||
|
*/
|
||||||
|
if ((rdataset->type == dns_rdatatype_a ||
|
||||||
|
rdataset->type == dns_rdatatype_aaaa) &&
|
||||||
|
!is_answeraddress_allowed(view, name,
|
||||||
|
rdataset)) {
|
||||||
|
return (DNS_R_SERVFAIL);
|
||||||
|
}
|
||||||
|
|
||||||
if (rdataset->type == type && !found_cname) {
|
if (rdataset->type == type && !found_cname) {
|
||||||
/*
|
/*
|
||||||
* We've found an ordinary answer.
|
* We've found an ordinary answer.
|
||||||
@@ -5284,6 +5426,14 @@ answer_response(fetchctx_t *fctx) {
|
|||||||
&tname);
|
&tname);
|
||||||
if (result != ISC_R_SUCCESS)
|
if (result != ISC_R_SUCCESS)
|
||||||
return (result);
|
return (result);
|
||||||
|
/* Apply filters on the target name. */
|
||||||
|
if (!is_answertarget_allowed(view,
|
||||||
|
name,
|
||||||
|
rdataset->type,
|
||||||
|
&tname,
|
||||||
|
&fctx->domain)) {
|
||||||
|
return (DNS_R_SERVFAIL);
|
||||||
|
}
|
||||||
} else if (rdataset->type == dns_rdatatype_rrsig
|
} else if (rdataset->type == dns_rdatatype_rrsig
|
||||||
&& rdataset->covers ==
|
&& rdataset->covers ==
|
||||||
dns_rdatatype_cname
|
dns_rdatatype_cname
|
||||||
@@ -5386,6 +5536,8 @@ answer_response(fetchctx_t *fctx) {
|
|||||||
rdataset != NULL;
|
rdataset != NULL;
|
||||||
rdataset = ISC_LIST_NEXT(rdataset, link)) {
|
rdataset = ISC_LIST_NEXT(rdataset, link)) {
|
||||||
isc_boolean_t found_dname = ISC_FALSE;
|
isc_boolean_t found_dname = ISC_FALSE;
|
||||||
|
dns_name_t *dname_name;
|
||||||
|
|
||||||
found = ISC_FALSE;
|
found = ISC_FALSE;
|
||||||
aflag = 0;
|
aflag = 0;
|
||||||
if (rdataset->type == dns_rdatatype_dname) {
|
if (rdataset->type == dns_rdatatype_dname) {
|
||||||
@@ -5415,6 +5567,15 @@ answer_response(fetchctx_t *fctx) {
|
|||||||
return (result);
|
return (result);
|
||||||
else
|
else
|
||||||
found_dname = ISC_TRUE;
|
found_dname = ISC_TRUE;
|
||||||
|
|
||||||
|
dname_name = dns_fixedname_name(&dname);
|
||||||
|
if (!is_answertarget_allowed(view,
|
||||||
|
qname,
|
||||||
|
rdataset->type,
|
||||||
|
dname_name,
|
||||||
|
&fctx->domain)) {
|
||||||
|
return (DNS_R_SERVFAIL);
|
||||||
|
}
|
||||||
} else if (rdataset->type == dns_rdatatype_rrsig
|
} else if (rdataset->type == dns_rdatatype_rrsig
|
||||||
&& rdataset->covers ==
|
&& rdataset->covers ==
|
||||||
dns_rdatatype_dname) {
|
dns_rdatatype_dname) {
|
||||||
|
@@ -15,7 +15,7 @@
|
|||||||
* PERFORMANCE OF THIS SOFTWARE.
|
* PERFORMANCE OF THIS SOFTWARE.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/* $Id: view.c,v 1.153 2009/01/27 22:29:59 jinmei Exp $ */
|
/* $Id: view.c,v 1.154 2009/05/29 22:22:37 jinmei Exp $ */
|
||||||
|
|
||||||
/*! \file */
|
/*! \file */
|
||||||
|
|
||||||
@@ -40,6 +40,7 @@
|
|||||||
#include <dns/masterdump.h>
|
#include <dns/masterdump.h>
|
||||||
#include <dns/order.h>
|
#include <dns/order.h>
|
||||||
#include <dns/peer.h>
|
#include <dns/peer.h>
|
||||||
|
#include <dns/rbt.h>
|
||||||
#include <dns/rdataset.h>
|
#include <dns/rdataset.h>
|
||||||
#include <dns/request.h>
|
#include <dns/request.h>
|
||||||
#include <dns/resolver.h>
|
#include <dns/resolver.h>
|
||||||
@@ -178,6 +179,10 @@ dns_view_create(isc_mem_t *mctx, dns_rdataclass_t rdclass,
|
|||||||
view->notifyacl = NULL;
|
view->notifyacl = NULL;
|
||||||
view->updateacl = NULL;
|
view->updateacl = NULL;
|
||||||
view->upfwdacl = NULL;
|
view->upfwdacl = NULL;
|
||||||
|
view->denyansweracl = NULL;
|
||||||
|
view->answeracl_exclude = NULL;
|
||||||
|
view->denyanswernames = NULL;
|
||||||
|
view->answernames_exclude = NULL;
|
||||||
view->requestixfr = ISC_TRUE;
|
view->requestixfr = ISC_TRUE;
|
||||||
view->provideixfr = ISC_TRUE;
|
view->provideixfr = ISC_TRUE;
|
||||||
view->maxcachettl = 7 * 24 * 3600;
|
view->maxcachettl = 7 * 24 * 3600;
|
||||||
@@ -313,6 +318,14 @@ destroy(dns_view_t *view) {
|
|||||||
dns_acl_detach(&view->updateacl);
|
dns_acl_detach(&view->updateacl);
|
||||||
if (view->upfwdacl != NULL)
|
if (view->upfwdacl != NULL)
|
||||||
dns_acl_detach(&view->upfwdacl);
|
dns_acl_detach(&view->upfwdacl);
|
||||||
|
if (view->denyansweracl != NULL)
|
||||||
|
dns_acl_detach(&view->denyansweracl);
|
||||||
|
if (view->answeracl_exclude != NULL)
|
||||||
|
dns_rbt_destroy(&view->answeracl_exclude);
|
||||||
|
if (view->denyanswernames != NULL)
|
||||||
|
dns_rbt_destroy(&view->denyanswernames);
|
||||||
|
if (view->answernames_exclude != NULL)
|
||||||
|
dns_rbt_destroy(&view->answernames_exclude);
|
||||||
if (view->delonly != NULL) {
|
if (view->delonly != NULL) {
|
||||||
dns_name_t *name;
|
dns_name_t *name;
|
||||||
int i;
|
int i;
|
||||||
|
@@ -15,7 +15,7 @@
|
|||||||
* PERFORMANCE OF THIS SOFTWARE.
|
* PERFORMANCE OF THIS SOFTWARE.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/* $Id: namedconf.c,v 1.95 2009/03/04 02:42:31 each Exp $ */
|
/* $Id: namedconf.c,v 1.96 2009/05/29 22:22:37 jinmei Exp $ */
|
||||||
|
|
||||||
/*! \file */
|
/*! \file */
|
||||||
|
|
||||||
@@ -736,6 +736,34 @@ static cfg_type_t cfg_type_optional_exclude = {
|
|||||||
"optional_exclude", parse_optional_keyvalue, print_keyvalue,
|
"optional_exclude", parse_optional_keyvalue, print_keyvalue,
|
||||||
doc_optional_keyvalue, &cfg_rep_list, &exclude_kw };
|
doc_optional_keyvalue, &cfg_rep_list, &exclude_kw };
|
||||||
|
|
||||||
|
static keyword_type_t exceptionnames_kw = { "except-from", &cfg_type_namelist };
|
||||||
|
|
||||||
|
static cfg_type_t cfg_type_optional_exceptionnames = {
|
||||||
|
"optional_allow", parse_optional_keyvalue, print_keyvalue,
|
||||||
|
doc_optional_keyvalue, &cfg_rep_list, &exceptionnames_kw };
|
||||||
|
|
||||||
|
static cfg_tuplefielddef_t denyaddresses_fields[] = {
|
||||||
|
{ "acl", &cfg_type_bracketed_aml, 0 },
|
||||||
|
{ "except-from", &cfg_type_optional_exceptionnames, 0 },
|
||||||
|
{ NULL, NULL, 0 }
|
||||||
|
};
|
||||||
|
|
||||||
|
static cfg_type_t cfg_type_denyaddresses = {
|
||||||
|
"denyaddresses", cfg_parse_tuple, cfg_print_tuple, cfg_doc_tuple,
|
||||||
|
&cfg_rep_tuple, denyaddresses_fields
|
||||||
|
};
|
||||||
|
|
||||||
|
static cfg_tuplefielddef_t denyaliases_fields[] = {
|
||||||
|
{ "name", &cfg_type_namelist, 0 },
|
||||||
|
{ "except-from", &cfg_type_optional_exceptionnames, 0 },
|
||||||
|
{ NULL, NULL, 0 }
|
||||||
|
};
|
||||||
|
|
||||||
|
static cfg_type_t cfg_type_denyaliases = {
|
||||||
|
"denyaliases", cfg_parse_tuple, cfg_print_tuple, cfg_doc_tuple,
|
||||||
|
&cfg_rep_tuple, denyaliases_fields
|
||||||
|
};
|
||||||
|
|
||||||
static cfg_type_t cfg_type_algorithmlist = {
|
static cfg_type_t cfg_type_algorithmlist = {
|
||||||
"algorithmlist", cfg_parse_bracketed_list, cfg_print_bracketed_list,
|
"algorithmlist", cfg_parse_bracketed_list, cfg_print_bracketed_list,
|
||||||
cfg_doc_bracketed_list, &cfg_rep_list, &cfg_type_astring };
|
cfg_doc_bracketed_list, &cfg_rep_list, &cfg_type_astring };
|
||||||
@@ -813,6 +841,8 @@ view_clauses[] = {
|
|||||||
{ "check-names", &cfg_type_checknames, CFG_CLAUSEFLAG_MULTI },
|
{ "check-names", &cfg_type_checknames, CFG_CLAUSEFLAG_MULTI },
|
||||||
{ "cleaning-interval", &cfg_type_uint32, 0 },
|
{ "cleaning-interval", &cfg_type_uint32, 0 },
|
||||||
{ "clients-per-query", &cfg_type_uint32, 0 },
|
{ "clients-per-query", &cfg_type_uint32, 0 },
|
||||||
|
{ "deny-answer-addresses", &cfg_type_denyaddresses, 0 },
|
||||||
|
{ "deny-answer-aliases", &cfg_type_denyaliases, 0 },
|
||||||
{ "disable-algorithms", &cfg_type_disablealgorithm,
|
{ "disable-algorithms", &cfg_type_disablealgorithm,
|
||||||
CFG_CLAUSEFLAG_MULTI },
|
CFG_CLAUSEFLAG_MULTI },
|
||||||
{ "disable-empty-zone", &cfg_type_astring, CFG_CLAUSEFLAG_MULTI },
|
{ "disable-empty-zone", &cfg_type_astring, CFG_CLAUSEFLAG_MULTI },
|
||||||
|
Reference in New Issue
Block a user