2
0
mirror of https://gitlab.isc.org/isc-projects/bind9 synced 2025-08-30 05:57:52 +00:00

Merge branch 'master' of ssh://repo.isc.org/proj/git/prod/bind9

This commit is contained in:
Tinderbox User 2014-08-30 01:01:25 +00:00
commit 2272d9a445
46 changed files with 1984 additions and 660 deletions

33
CHANGES
View File

@ -1,3 +1,36 @@
3937. [func] Added some debug logging to better indicate the
conditions causing SERVFAILs when resolving.
[RT #35538]
3936. [func] Added authoritative support for the EDNS Client
Subnet (ECS) option.
ACLs can now include "ecs" elements which specify
an address or network prefix; if an ECS option is
included in a DNS query, then the address encoded
in the option will be matched against "ecs" ACL
elements.
Also, if an ECS address is included in a query,
then it will be used instead of the client source
address when matching "geoip" ACL elements. This
behavior can be overridden with "geoip-use-ecs no;".
When "ecs" or "geoip" ACL elements are used to
select a view for a query, the response will include
an ECS option to indicate which client network the
answer is valid for.
(Thanks to Vincent Bernat.) [RT #36781]
3935. [bug] "geoip asnum" ACL elements would not match unless
the full organization name was specified. They
can now match against the AS number alone (e.g.,
AS1234). [RT #36945]
3934. [bug] Catch bad 'sit-secret' in named-checkconf. Improve
sit-secret documentation. [RT #36980]
3933. [bug] Corrected the implementation of dns_rdata_casecompare()
for the HIP rdata type. [RT #36911]

6
README
View File

@ -56,6 +56,12 @@ BIND 9.11.0
BIND 9.11.0 includes a number of changes from BIND 9.10 and earlier
releases. New features include:
- The EDNS Client Subnet (ECS) option is now supported for
authoritative servers; if a query contains an ECS option
then ACLs containing "geoip" or "ecs" elements can match
against the the address encoded in the option. This can be
used to select a view for a query, so that different answers
can be provided depending on the client network.
- The EDNS EXPIRE option has been implemented on the client
side, allowing a slave server to set the expiration timer
correctly when transferring zone data from another slave

View File

@ -122,6 +122,7 @@
#endif
#define SIT_SIZE 24U /* 8 + 4 + 4 + 8 */
#define ECS_SIZE 20U /* 2 + 1 + 1 + [0..16] */
/*% nameserver client manager structure */
struct ns_clientmgr {
@ -244,7 +245,8 @@ static void ns_client_dumpmessage(ns_client_t *client, const char *reason);
static isc_result_t get_client(ns_clientmgr_t *manager, ns_interface_t *ifp,
dns_dispatch_t *disp, isc_boolean_t tcp);
static inline isc_boolean_t
allowed(isc_netaddr_t *addr, dns_name_t *signer, dns_acl_t *acl);
allowed(isc_netaddr_t *addr, dns_name_t *signer, isc_netaddr_t *ecs_addr,
isc_uint8_t ecs_addrlen, isc_uint8_t *ecs_scope, dns_acl_t *acl);
#ifdef ISC_PLATFORM_USESIT
static void compute_sit(ns_client_t *client, isc_uint32_t when,
isc_uint32_t nonce, isc_buffer_t *buf);
@ -1042,7 +1044,8 @@ client_send(ns_client_t *client) {
if (client->message->tsigkey != NULL)
name = &client->message->tsigkey->name;
if (client->view->nocasecompress == NULL ||
!allowed(&netaddr, name, client->view->nocasecompress))
!allowed(&netaddr, name, NULL, 0, NULL,
client->view->nocasecompress))
{
dns_compress_setsensitive(&cctx, ISC_TRUE);
}
@ -1381,6 +1384,7 @@ isc_result_t
ns_client_addopt(ns_client_t *client, dns_message_t *message,
dns_rdataset_t **opt)
{
unsigned char ecs[ECS_SIZE];
char nsid[BUFSIZ], *nsidp;
#ifdef ISC_PLATFORM_USESIT
unsigned char sit[SIT_SIZE];
@ -1459,6 +1463,38 @@ ns_client_addopt(ns_client_t *client, dns_message_t *message,
ednsopts[count].value = expire;
count++;
}
if (((client->attributes & NS_CLIENTATTR_HAVEECS) != 0) &&
(client->ecs_addr.family == AF_INET ||
client->ecs_addr.family == AF_INET6))
{
int i, addrbytes = (client->ecs_addrlen + 7) / 8;
isc_uint8_t *paddr;
isc_buffer_t buf;
/* Add client subnet option. */
isc_buffer_init(&buf, ecs, sizeof(ecs));
if (client->ecs_addr.family == AF_INET)
isc_buffer_putuint16(&buf, 1);
else
isc_buffer_putuint16(&buf, 2);
isc_buffer_putuint8(&buf, client->ecs_addrlen);
isc_buffer_putuint8(&buf, client->ecs_scope);
paddr = (isc_uint8_t *) &client->ecs_addr.type;
for (i = 0; i < addrbytes; i++) {
unsigned char uc;
uc = paddr[i];
if (i == addrbytes - 1 &&
((client->ecs_addrlen % 8) != 0))
uc &= (1U << (8 - (client->ecs_addrlen % 8)));
isc_buffer_putuint8(&buf, uc);
}
ednsopts[count].code = DNS_OPT_CLIENT_SUBNET;
ednsopts[count].length = addrbytes + 4;
ednsopts[count].value = ecs;
count++;
}
result = dns_message_buildopt(message, opt, 0, udpsize, flags,
ednsopts, count);
@ -1466,14 +1502,17 @@ ns_client_addopt(ns_client_t *client, dns_message_t *message,
}
static inline isc_boolean_t
allowed(isc_netaddr_t *addr, dns_name_t *signer, dns_acl_t *acl) {
allowed(isc_netaddr_t *addr, dns_name_t *signer,
isc_netaddr_t *ecs_addr, isc_uint8_t ecs_addrlen,
isc_uint8_t *ecs_scope, dns_acl_t *acl)
{
int match;
isc_result_t result;
if (acl == NULL)
return (ISC_TRUE);
result = dns_acl_match(addr, signer, acl, &ns_g_server->aclenv,
&match, NULL);
result = dns_acl_match2(addr, signer, ecs_addr, ecs_addrlen, ecs_scope,
acl, &ns_g_server->aclenv, &match, NULL);
if (result == ISC_R_SUCCESS && match > 0)
return (ISC_TRUE);
return (ISC_FALSE);
@ -1536,8 +1575,10 @@ ns_client_isself(dns_view_t *myview, dns_tsigkey_t *mykey,
tsig = dns_tsigkey_identity(mykey);
}
if (allowed(&netsrc, tsig, view->matchclients) &&
allowed(&netdst, tsig, view->matchdestinations))
if (allowed(&netsrc, tsig, NULL, 0, NULL,
view->matchclients) &&
allowed(&netdst, tsig, NULL, 0, NULL,
view->matchdestinations))
break;
}
return (ISC_TF(view == myview));
@ -1718,6 +1759,81 @@ process_sit(ns_client_t *client, isc_buffer_t *buf, size_t optlen) {
}
#endif
static isc_result_t
process_ecs(ns_client_t *client, isc_buffer_t *buf, size_t optlen) {
isc_uint16_t family;
isc_uint8_t addrlen, addrbytes, scope, *paddr;
isc_netaddr_t caddr;
int i;
if (optlen < 4) {
ns_client_log(client, NS_LOGCATEGORY_CLIENT,
NS_LOGMODULE_CLIENT, ISC_LOG_DEBUG(2),
"EDNS client subnet option too short");
return (DNS_R_FORMERR);
}
family = isc_buffer_getuint16(buf);
addrlen = isc_buffer_getuint8(buf);
scope = isc_buffer_getuint8(buf);
optlen -= 4;
if (scope != 0U) {
ns_client_log(client, NS_LOGCATEGORY_CLIENT,
NS_LOGMODULE_CLIENT, ISC_LOG_DEBUG(2),
"EDNS client subnet option: invalid scope");
return (DNS_R_FORMERR);
}
memset(&caddr, 0, sizeof(caddr));
switch (family) {
case 1:
if (addrlen > 32U)
goto invalid_length;
caddr.family = AF_INET;
break;
case 2:
if (addrlen > 128U) {
invalid_length:
ns_client_log(client, NS_LOGCATEGORY_CLIENT,
NS_LOGMODULE_CLIENT, ISC_LOG_DEBUG(2),
"EDNS client subnet option: invalid "
"address length (%u) for %s",
addrlen, family == 1 ? "IPv4" : "IPv6");
return (DNS_R_FORMERR);
}
caddr.family = AF_INET6;
break;
default:
ns_client_log(client, NS_LOGCATEGORY_CLIENT,
NS_LOGMODULE_CLIENT, ISC_LOG_DEBUG(2),
"EDNS client subnet option: invalid family");
return (DNS_R_FORMERR);
}
addrbytes = (addrlen + 7) / 8;
if (isc_buffer_remaininglength(buf) < addrbytes) {
ns_client_log(client, NS_LOGCATEGORY_CLIENT,
NS_LOGMODULE_CLIENT, ISC_LOG_DEBUG(2),
"EDNS client subnet option: address too short");
return (DNS_R_FORMERR);
}
paddr = (isc_uint8_t *) &caddr.type;
for (i = 0; i < addrbytes; i++) {
paddr[i] = isc_buffer_getuint8(buf);
optlen--;
}
memmove(&client->ecs_addr, &caddr, sizeof(caddr));
client->ecs_addrlen = addrlen;
client->ecs_scope = 0;
client->attributes |= NS_CLIENTATTR_HAVEECS;
isc_buffer_forward(buf, optlen);
return (ISC_R_SUCCESS);
}
static isc_result_t
process_opt(ns_client_t *client, dns_rdataset_t *opt) {
dns_rdata_t rdata;
@ -1788,6 +1904,15 @@ process_opt(ns_client_t *client, dns_rdataset_t *opt) {
client->attributes |= NS_CLIENTATTR_WANTEXPIRE;
isc_buffer_forward(&optbuf, optlen);
break;
case DNS_OPT_CLIENT_SUBNET:
result = process_ecs(client, &optbuf, optlen);
if (result != ISC_R_SUCCESS) {
ns_client_error(client, result);
goto cleanup;
}
isc_stats_increment(ns_g_server->nsstats,
dns_nsstatscounter_ecsopt);
break;
default:
isc_stats_increment(ns_g_server->nsstats,
dns_nsstatscounter_otheropt);
@ -1925,7 +2050,6 @@ client_request(isc_task_t *task, isc_event_t *event) {
* client_newconn.
*/
if (!TCP_CLIENT(client)) {
if (ns_g_server->blackholeacl != NULL &&
dns_acl_match(&netaddr, NULL, ns_g_server->blackholeacl,
&ns_g_server->aclenv,
@ -2033,6 +2157,10 @@ client_request(isc_task_t *task, isc_event_t *event) {
opt = NULL;
else
opt = dns_message_getopt(client->message);
client->ecs_addrlen = 0;
client->ecs_scope = 0;
if (opt != NULL) {
/*
* Are we dropping all EDNS queries?
@ -2117,17 +2245,29 @@ client_request(isc_task_t *task, isc_event_t *event) {
client->message->rdclass == dns_rdataclass_any)
{
dns_name_t *tsig = NULL;
isc_netaddr_t *addr = NULL;
isc_uint8_t *scope = NULL;
sigresult = dns_message_rechecksig(client->message,
view);
if (sigresult == ISC_R_SUCCESS)
tsig = dns_tsigkey_identity(client->message->tsigkey);
if (sigresult == ISC_R_SUCCESS) {
dns_tsigkey_t *tsigkey;
if (allowed(&netaddr, tsig, view->matchclients) &&
allowed(&client->destaddr, tsig,
view->matchdestinations) &&
!((client->message->flags & DNS_MESSAGEFLAG_RD)
== 0 && view->matchrecursiveonly))
tsigkey = client->message->tsigkey;
tsig = dns_tsigkey_identity(tsigkey);
}
if ((client->attributes & NS_CLIENTATTR_HAVEECS) != 0) {
addr = &client->ecs_addr;
scope = &client->ecs_scope;
}
if (allowed(&netaddr, tsig, addr, client->ecs_addrlen,
scope, view->matchclients) &&
allowed(&client->destaddr, tsig, NULL,
0, NULL, view->matchdestinations) &&
!(view->matchrecursiveonly &&
(client->message->flags & DNS_MESSAGEFLAG_RD) == 0))
{
dns_view_attach(view, &client->view);
break;
@ -2519,6 +2659,8 @@ client_create(ns_clientmgr_t *manager, ns_client_t **clientp) {
client->recursionquota = NULL;
client->interface = NULL;
client->peeraddr_valid = ISC_FALSE;
client->ecs_addrlen = 0;
client->ecs_scope = 0;
#ifdef ALLOW_FILTER_AAAA
client->filter_aaaa = dns_aaaa_ok;
#endif
@ -3055,6 +3197,8 @@ ns_client_checkaclsilent(ns_client_t *client, isc_netaddr_t *netaddr,
{
isc_result_t result;
isc_netaddr_t tmpnetaddr;
isc_netaddr_t *ecs_addr = NULL;
isc_uint8_t ecs_addrlen = 0;
int match;
if (acl == NULL) {
@ -3069,11 +3213,18 @@ ns_client_checkaclsilent(ns_client_t *client, isc_netaddr_t *netaddr,
netaddr = &tmpnetaddr;
}
result = dns_acl_match(netaddr, client->signer, acl,
&ns_g_server->aclenv, &match, NULL);
if ((client->attributes & NS_CLIENTATTR_HAVEECS) != 0) {
ecs_addr = &client->ecs_addr;
ecs_addrlen = client->ecs_addrlen;
}
result = dns_acl_match2(netaddr, client->signer,
ecs_addr, ecs_addrlen, NULL, acl,
&ns_g_server->aclenv, &match, NULL);
if (result != ISC_R_SUCCESS)
goto deny; /* Internal error, already logged. */
if (match > 0)
goto allow;
goto deny; /* Negative match or no match. */

View File

@ -177,6 +177,11 @@ options {\n\
nsec3-test-zone no;\n\
allow-new-zones no;\n\
"
#ifdef HAVE_GEOIP
"\
geoip-use-ecs yes;\n\
"
#endif
#ifdef ALLOW_FILTER_AAAA
" filter-aaaa-on-v4 no;\n\
filter-aaaa-on-v6 no;\n\

View File

@ -137,9 +137,15 @@ struct ns_client {
isc_quota_t *tcpquota;
isc_quota_t *recursionquota;
ns_interface_t *interface;
isc_sockaddr_t peeraddr;
isc_boolean_t peeraddr_valid;
isc_netaddr_t destaddr;
isc_netaddr_t ecs_addr; /*%< EDNS client subnet */
isc_uint8_t ecs_addrlen;
isc_uint8_t ecs_scope;
struct in6_pktinfo pktinfo;
isc_dscp_t dscp;
isc_event_t ctlevent;
@ -187,6 +193,7 @@ typedef ISC_LIST(ns_client_t) client_list_t;
#define NS_CLIENTATTR_WANTEXPIRE 0x0800 /*%< return seconds to expire */
#define NS_CLIENTATTR_HAVEEXPIRE 0x1000 /*%< return seconds to expire */
#define NS_CLIENTATTR_WANTOPT 0x2000 /*%< add opt to reply */
#define NS_CLIENTATTR_HAVEECS 0x4000 /*%< sent an ECS option */
extern unsigned int ns_client_requests;

View File

@ -182,18 +182,19 @@ enum {
dns_nsstatscounter_nsidopt = 43,
dns_nsstatscounter_expireopt = 44,
dns_nsstatscounter_otheropt = 45,
dns_nsstatscounter_ecsopt = 46,
#ifdef ISC_PLATFORM_USESIT
dns_nsstatscounter_sitopt = 46,
dns_nsstatscounter_sitbadsize = 47,
dns_nsstatscounter_sitbadtime = 48,
dns_nsstatscounter_sitnomatch = 49,
dns_nsstatscounter_sitmatch = 50,
dns_nsstatscounter_sitnew = 51,
dns_nsstatscounter_sitopt = 47,
dns_nsstatscounter_sitbadsize = 48,
dns_nsstatscounter_sitbadtime = 49,
dns_nsstatscounter_sitnomatch = 50,
dns_nsstatscounter_sitmatch = 51,
dns_nsstatscounter_sitnew = 52,
dns_nsstatscounter_max = 52
dns_nsstatscounter_max = 53
#else
dns_nsstatscounter_max = 46
dns_nsstatscounter_max = 47
#endif
};

View File

@ -23,6 +23,7 @@
#include <isc/hex.h>
#include <isc/mem.h>
#include <isc/print.h>
#include <isc/serial.h>
#include <isc/stats.h>
#include <isc/util.h>
@ -125,21 +126,25 @@
DNS_RDATASETATTR_NOQNAME) != 0)
#if 0
#define CTRACE(m) isc_log_write(ns_g_lctx, \
NS_LOGCATEGORY_CLIENT, \
NS_LOGMODULE_QUERY, \
ISC_LOG_DEBUG(3), \
"client %p: %s", client, (m))
#define QTRACE(m) isc_log_write(ns_g_lctx, \
NS_LOGCATEGORY_GENERAL, \
NS_LOGMODULE_QUERY, \
ISC_LOG_DEBUG(3), \
"query %p: %s", query, (m))
#define CTRACE(l,m) do { \
if (client != NULL && client->query.qname != NULL) { \
char qbuf[DNS_NAME_FORMATSIZE]; \
dns_name_format(client->query.qname, qbuf, sizeof(qbuf)); \
isc_log_write(ns_g_lctx, \
NS_LOGCATEGORY_CLIENT, NS_LOGMODULE_QUERY, \
l, "client %p (%s): %s", client, qbuf, (m)); \
} else { \
isc_log_write(ns_g_lctx, \
NS_LOGCATEGORY_CLIENT, NS_LOGMODULE_QUERY, \
l, "client %p (<unknown-name>): %s", \
client, (m)); \
} \
} while(0)
#else
#define CTRACE(m) ((void)m)
#define QTRACE(m) ((void)m)
#define CTRACE(l,m) ((void)m)
#endif
#define DNS_GETDB_NOEXACT 0x01U
#define DNS_GETDB_NOLOG 0x02U
#define DNS_GETDB_PARTIAL 0x04U
@ -312,13 +317,13 @@ static inline void
query_putrdataset(ns_client_t *client, dns_rdataset_t **rdatasetp) {
dns_rdataset_t *rdataset = *rdatasetp;
CTRACE("query_putrdataset");
CTRACE(ISC_LOG_DEBUG(3), "query_putrdataset");
if (rdataset != NULL) {
if (dns_rdataset_isassociated(rdataset))
dns_rdataset_disassociate(rdataset);
dns_message_puttemprdataset(client->message, rdatasetp);
}
CTRACE("query_putrdataset: done");
CTRACE(ISC_LOG_DEBUG(3), "query_putrdataset: done");
}
static inline void
@ -425,7 +430,7 @@ query_newnamebuf(ns_client_t *client) {
isc_buffer_t *dbuf;
isc_result_t result;
CTRACE("query_newnamebuf");
CTRACE(ISC_LOG_DEBUG(3), "query_newnamebuf");
/*%
* Allocate a name buffer.
*/
@ -433,12 +438,13 @@ query_newnamebuf(ns_client_t *client) {
dbuf = NULL;
result = isc_buffer_allocate(client->mctx, &dbuf, 1024);
if (result != ISC_R_SUCCESS) {
CTRACE("query_newnamebuf: isc_buffer_allocate failed: done");
CTRACE(ISC_LOG_DEBUG(3),
"query_newnamebuf: isc_buffer_allocate failed: done");
return (result);
}
ISC_LIST_APPEND(client->query.namebufs, dbuf, link);
CTRACE("query_newnamebuf: done");
CTRACE(ISC_LOG_DEBUG(3), "query_newnamebuf: done");
return (ISC_R_SUCCESS);
}
@ -448,7 +454,7 @@ query_getnamebuf(ns_client_t *client) {
isc_result_t result;
isc_region_t r;
CTRACE("query_getnamebuf");
CTRACE(ISC_LOG_DEBUG(3), "query_getnamebuf");
/*%
* Return a name buffer with space for a maximal name, allocating
* a new one if necessary.
@ -457,7 +463,8 @@ query_getnamebuf(ns_client_t *client) {
if (ISC_LIST_EMPTY(client->query.namebufs)) {
result = query_newnamebuf(client);
if (result != ISC_R_SUCCESS) {
CTRACE("query_getnamebuf: query_newnamebuf failed: done");
CTRACE(ISC_LOG_DEBUG(3),
"query_getnamebuf: query_newnamebuf failed: done");
return (NULL);
}
}
@ -468,7 +475,8 @@ query_getnamebuf(ns_client_t *client) {
if (r.length < 255) {
result = query_newnamebuf(client);
if (result != ISC_R_SUCCESS) {
CTRACE("query_getnamebuf: query_newnamebuf failed: done");
CTRACE(ISC_LOG_DEBUG(3),
"query_getnamebuf: query_newnamebuf failed: done");
return (NULL);
}
@ -476,7 +484,7 @@ query_getnamebuf(ns_client_t *client) {
isc_buffer_availableregion(dbuf, &r);
INSIST(r.length >= 255);
}
CTRACE("query_getnamebuf: done");
CTRACE(ISC_LOG_DEBUG(3), "query_getnamebuf: done");
return (dbuf);
}
@ -484,7 +492,7 @@ static inline void
query_keepname(ns_client_t *client, dns_name_t *name, isc_buffer_t *dbuf) {
isc_region_t r;
CTRACE("query_keepname");
CTRACE(ISC_LOG_DEBUG(3), "query_keepname");
/*%
* 'name' is using space in 'dbuf', but 'dbuf' has not yet been
* adjusted to take account of that. We do the adjustment.
@ -508,14 +516,14 @@ query_releasename(ns_client_t *client, dns_name_t **namep) {
* rights on the buffer.
*/
CTRACE("query_releasename");
CTRACE(ISC_LOG_DEBUG(3), "query_releasename");
if (dns_name_hasbuffer(name)) {
INSIST((client->query.attributes & NS_QUERYATTR_NAMEBUFUSED)
!= 0);
client->query.attributes &= ~NS_QUERYATTR_NAMEBUFUSED;
}
dns_message_puttempname(client->message, namep);
CTRACE("query_releasename: done");
CTRACE(ISC_LOG_DEBUG(3), "query_releasename: done");
}
static inline dns_name_t *
@ -528,11 +536,12 @@ query_newname(ns_client_t *client, isc_buffer_t *dbuf,
REQUIRE((client->query.attributes & NS_QUERYATTR_NAMEBUFUSED) == 0);
CTRACE("query_newname");
CTRACE(ISC_LOG_DEBUG(3), "query_newname");
name = NULL;
result = dns_message_gettempname(client->message, &name);
if (result != ISC_R_SUCCESS) {
CTRACE("query_newname: dns_message_gettempname failed: done");
CTRACE(ISC_LOG_DEBUG(3),
"query_newname: dns_message_gettempname failed: done");
return (NULL);
}
isc_buffer_availableregion(dbuf, &r);
@ -541,7 +550,7 @@ query_newname(ns_client_t *client, isc_buffer_t *dbuf,
dns_name_setbuffer(name, nbuf);
client->query.attributes |= NS_QUERYATTR_NAMEBUFUSED;
CTRACE("query_newname: done");
CTRACE(ISC_LOG_DEBUG(3), "query_newname: done");
return (name);
}
@ -550,17 +559,18 @@ query_newrdataset(ns_client_t *client) {
dns_rdataset_t *rdataset;
isc_result_t result;
CTRACE("query_newrdataset");
CTRACE(ISC_LOG_DEBUG(3), "query_newrdataset");
rdataset = NULL;
result = dns_message_gettemprdataset(client->message, &rdataset);
if (result != ISC_R_SUCCESS) {
CTRACE("query_newrdataset: "
CTRACE(ISC_LOG_DEBUG(3),
"query_newrdataset: "
"dns_message_gettemprdataset failed: done");
return (NULL);
}
dns_rdataset_init(rdataset);
CTRACE("query_newrdataset: done");
CTRACE(ISC_LOG_DEBUG(3), "query_newrdataset: done");
return (rdataset);
}
@ -727,8 +737,10 @@ query_validatezonedb(ns_client_t *client, dns_name_t *name,
* Get the current version of this database.
*/
dbversion = query_findversion(client, db);
if (dbversion == NULL)
if (dbversion == NULL) {
CTRACE(ISC_LOG_ERROR, "unable to get db version");
return (DNS_R_SERVFAIL);
}
if ((options & DNS_GETDB_IGNOREACL) != 0)
goto approved;
@ -1191,7 +1203,7 @@ query_isduplicate(ns_client_t *client, dns_name_t *name,
dns_name_t *mname = NULL;
isc_result_t result;
CTRACE("query_isduplicate");
CTRACE(ISC_LOG_DEBUG(3), "query_isduplicate");
for (section = DNS_SECTION_ANSWER;
section <= DNS_SECTION_ADDITIONAL;
@ -1202,7 +1214,8 @@ query_isduplicate(ns_client_t *client, dns_name_t *name,
/*
* We've already got this RRset in the response.
*/
CTRACE("query_isduplicate: true: done");
CTRACE(ISC_LOG_DEBUG(3),
"query_isduplicate: true: done");
return (ISC_TRUE);
} else if (result == DNS_R_NXRRSET) {
/*
@ -1218,7 +1231,7 @@ query_isduplicate(ns_client_t *client, dns_name_t *name,
if (mnamep != NULL)
*mnamep = mname;
CTRACE("query_isduplicate: false: done");
CTRACE(ISC_LOG_DEBUG(3), "query_isduplicate: false: done");
return (ISC_FALSE);
}
@ -1245,7 +1258,7 @@ query_addadditional(void *arg, dns_name_t *name, dns_rdatatype_t qtype) {
if (!WANTDNSSEC(client) && dns_rdatatype_isdnssec(qtype))
return (ISC_R_SUCCESS);
CTRACE("query_addadditional");
CTRACE(ISC_LOG_DEBUG(3), "query_addadditional");
/*
* Initialization.
@ -1301,7 +1314,7 @@ query_addadditional(void *arg, dns_name_t *name, dns_rdatatype_t qtype) {
if (result != ISC_R_SUCCESS)
goto try_cache;
CTRACE("query_addadditional: db_find");
CTRACE(ISC_LOG_DEBUG(3), "query_addadditional: db_find");
/*
* Since we are looking for authoritative data, we do not set
@ -1573,7 +1586,7 @@ query_addadditional(void *arg, dns_name_t *name, dns_rdatatype_t qtype) {
}
addname:
CTRACE("query_addadditional: addname");
CTRACE(ISC_LOG_DEBUG(3), "query_addadditional: addname");
/*
* If we haven't added anything, then we're done.
*/
@ -1613,7 +1626,7 @@ query_addadditional(void *arg, dns_name_t *name, dns_rdatatype_t qtype) {
}
cleanup:
CTRACE("query_addadditional: cleanup");
CTRACE(ISC_LOG_DEBUG(3), "query_addadditional: cleanup");
query_putrdataset(client, &rdataset);
if (sigrdataset != NULL)
query_putrdataset(client, &sigrdataset);
@ -1626,7 +1639,7 @@ query_addadditional(void *arg, dns_name_t *name, dns_rdatatype_t qtype) {
if (zone != NULL)
dns_zone_detach(&zone);
CTRACE("query_addadditional: done");
CTRACE(ISC_LOG_DEBUG(3), "query_addadditional: done");
return (eresult);
}
@ -1744,7 +1757,7 @@ query_addadditional2(void *arg, dns_name_t *name, dns_rdatatype_t qtype) {
dns_clientinfomethods_init(&cm, ns_client_sourceip);
dns_clientinfo_init(&ci, client, NULL);
CTRACE("query_addadditional2");
CTRACE(ISC_LOG_DEBUG(3), "query_addadditional2");
/*
* We treat type A additional section processing as if it
@ -1776,14 +1789,16 @@ query_addadditional2(void *arg, dns_name_t *name, dns_rdatatype_t qtype) {
if (result != ISC_R_SUCCESS)
goto findauthdb;
if (zone == NULL) {
CTRACE("query_addadditional2: auth zone not found");
CTRACE(ISC_LOG_DEBUG(3),
"query_addadditional2: auth zone not found");
goto try_cache;
}
/* Is the cached DB up-to-date? */
result = query_iscachevalid(zone, cdb, NULL, cversion);
if (result != ISC_R_SUCCESS) {
CTRACE("query_addadditional2: old auth additional cache");
CTRACE(ISC_LOG_DEBUG(3),
"query_addadditional2: old auth additional cache");
query_discardcache(client, rdataset_base, additionaltype,
type, &zone, &cdb, &cversion, &cnode,
&cfname);
@ -1796,7 +1811,8 @@ query_addadditional2(void *arg, dns_name_t *name, dns_rdatatype_t qtype) {
* ACL, since the result (not using this zone) would be same
* regardless of the result.
*/
CTRACE("query_addadditional2: negative auth additional cache");
CTRACE(ISC_LOG_DEBUG(3),
"query_addadditional2: negative auth additional cache");
dns_db_closeversion(cdb, &cversion, ISC_FALSE);
dns_db_detach(&cdb);
dns_zone_detach(&zone);
@ -1813,7 +1829,8 @@ query_addadditional2(void *arg, dns_name_t *name, dns_rdatatype_t qtype) {
}
/* We've got an active cache. */
CTRACE("query_addadditional2: auth additional cache");
CTRACE(ISC_LOG_DEBUG(3),
"query_addadditional2: auth additional cache");
dns_db_closeversion(cdb, &cversion, ISC_FALSE);
db = cdb;
node = cnode;
@ -1837,7 +1854,7 @@ query_addadditional2(void *arg, dns_name_t *name, dns_rdatatype_t qtype) {
goto try_cache;
}
CTRACE("query_addadditional2: db_find");
CTRACE(ISC_LOG_DEBUG(3), "query_addadditional2: db_find");
/*
* Since we are looking for authoritative data, we do not set
@ -1922,7 +1939,8 @@ query_addadditional2(void *arg, dns_name_t *name, dns_rdatatype_t qtype) {
result = query_iscachevalid(zone, cdb, client->query.gluedb, cversion);
if (result != ISC_R_SUCCESS) {
CTRACE("query_addadditional2: old glue additional cache");
CTRACE(ISC_LOG_DEBUG(3),
"query_addadditional2: old glue additional cache");
query_discardcache(client, rdataset_base, additionaltype,
type, &zone, &cdb, &cversion, &cnode,
&cfname);
@ -1931,14 +1949,15 @@ query_addadditional2(void *arg, dns_name_t *name, dns_rdatatype_t qtype) {
if (cnode == NULL) {
/* We have a negative cache. */
CTRACE("query_addadditional2: negative glue additional cache");
CTRACE(ISC_LOG_DEBUG(3),
"query_addadditional2: negative glue additional cache");
dns_db_closeversion(cdb, &cversion, ISC_FALSE);
dns_db_detach(&cdb);
goto cleanup;
}
/* Cache hit. */
CTRACE("query_addadditional2: glue additional cache");
CTRACE(ISC_LOG_DEBUG(3), "query_addadditional2: glue additional cache");
dns_db_closeversion(cdb, &cversion, ISC_FALSE);
db = cdb;
node = cnode;
@ -2121,7 +2140,7 @@ query_addadditional2(void *arg, dns_name_t *name, dns_rdatatype_t qtype) {
}
}
CTRACE("query_addadditional2: addname");
CTRACE(ISC_LOG_DEBUG(3), "query_addadditional2: addname");
/*
* If we haven't added anything, then we're done.
@ -2140,7 +2159,7 @@ query_addadditional2(void *arg, dns_name_t *name, dns_rdatatype_t qtype) {
fname = NULL;
cleanup:
CTRACE("query_addadditional2: cleanup");
CTRACE(ISC_LOG_DEBUG(3), "query_addadditional2: cleanup");
if (rdataset != NULL)
query_putrdataset(client, &rdataset);
@ -2159,7 +2178,7 @@ query_addadditional2(void *arg, dns_name_t *name, dns_rdatatype_t qtype) {
if (zone != NULL)
dns_zone_detach(&zone);
CTRACE("query_addadditional2: done");
CTRACE(ISC_LOG_DEBUG(3), "query_addadditional2: done");
return (eresult);
}
@ -2174,7 +2193,7 @@ query_addrdataset(ns_client_t *client, dns_name_t *fname,
* 'fname', a name in the response message for 'client'.
*/
CTRACE("query_addrdataset");
CTRACE(ISC_LOG_DEBUG(3), "query_addrdataset");
ISC_LIST_APPEND(fname->list, rdataset, link);
@ -2196,7 +2215,7 @@ query_addrdataset(ns_client_t *client, dns_name_t *fname,
additionalctx.rdataset = rdataset;
(void)dns_rdataset_additionaldata(rdataset, query_addadditional2,
&additionalctx);
CTRACE("query_addrdataset: done");
CTRACE(ISC_LOG_DEBUG(3), "query_addrdataset: done");
}
static isc_result_t
@ -2228,7 +2247,7 @@ query_dns64(ns_client_t *client, dns_name_t **namep, dns_rdataset_t *rdataset,
* stored in 'dbuf'. In this case, query_addrrset() guarantees that
* when it returns the name will either have been kept or released.
*/
CTRACE("query_dns64");
CTRACE(ISC_LOG_DEBUG(3), "query_dns64");
name = *namep;
mname = NULL;
mrdataset = NULL;
@ -2245,7 +2264,8 @@ query_dns64(ns_client_t *client, dns_name_t **namep, dns_rdataset_t *rdataset,
* We've already got an RRset of the given name and type.
* There's nothing else to do;
*/
CTRACE("query_dns64: dns_message_findname succeeded: done");
CTRACE(ISC_LOG_DEBUG(3),
"query_dns64: dns_message_findname succeeded: done");
if (dbuf != NULL)
query_releasename(client, namep);
return (ISC_R_SUCCESS);
@ -2376,7 +2396,7 @@ query_dns64(ns_client_t *client, dns_name_t **namep, dns_rdataset_t *rdataset,
dns_message_puttemprdatalist(client->message, &dns64_rdatalist);
}
CTRACE("query_dns64: done");
CTRACE(ISC_LOG_DEBUG(3), "query_dns64: done");
return (result);
}
@ -2395,7 +2415,7 @@ query_filter64(ns_client_t *client, dns_name_t **namep,
isc_result_t result;
unsigned int i;
CTRACE("query_filter64");
CTRACE(ISC_LOG_DEBUG(3), "query_filter64");
INSIST(client->query.dns64_aaaaok != NULL);
INSIST(client->query.dns64_aaaaoklen == dns_rdataset_count(rdataset));
@ -2415,7 +2435,8 @@ query_filter64(ns_client_t *client, dns_name_t **namep,
* We've already got an RRset of the given name and type.
* There's nothing else to do;
*/
CTRACE("query_filter64: dns_message_findname succeeded: done");
CTRACE(ISC_LOG_DEBUG(3),
"query_filter64: dns_message_findname succeeded: done");
if (dbuf != NULL)
query_releasename(client, namep);
return;
@ -2514,7 +2535,7 @@ query_filter64(ns_client_t *client, dns_name_t **namep,
if (dbuf != NULL)
query_releasename(client, &name);
CTRACE("query_filter64: done");
CTRACE(ISC_LOG_DEBUG(3), "query_filter64: done");
}
static void
@ -2536,7 +2557,7 @@ query_addrrset(ns_client_t *client, dns_name_t **namep,
* stored in 'dbuf'. In this case, query_addrrset() guarantees that
* when it returns the name will either have been kept or released.
*/
CTRACE("query_addrrset");
CTRACE(ISC_LOG_DEBUG(3), "query_addrrset");
name = *namep;
rdataset = *rdatasetp;
if (sigrdatasetp != NULL)
@ -2552,7 +2573,8 @@ query_addrrset(ns_client_t *client, dns_name_t **namep,
/*
* We've already got an RRset of the given name and type.
*/
CTRACE("query_addrrset: dns_message_findname succeeded: done");
CTRACE(ISC_LOG_DEBUG(3),
"query_addrrset: dns_message_findname succeeded: done");
if (dbuf != NULL)
query_releasename(client, namep);
if ((rdataset->attributes & DNS_RDATASETATTR_REQUIRED) != 0)
@ -2591,7 +2613,7 @@ query_addrrset(ns_client_t *client, dns_name_t **namep,
ISC_LIST_APPEND(mname->list, sigrdataset, link);
*sigrdatasetp = NULL;
}
CTRACE("query_addrrset: done");
CTRACE(ISC_LOG_DEBUG(3), "query_addrrset: done");
}
static inline isc_result_t
@ -2607,7 +2629,7 @@ query_addsoa(ns_client_t *client, dns_db_t *db, dns_dbversion_t *version,
dns_clientinfomethods_t cm;
dns_clientinfo_t ci;
CTRACE("query_addsoa");
CTRACE(ISC_LOG_DEBUG(3), "query_addsoa");
/*
* Initialization.
*/
@ -2635,12 +2657,14 @@ query_addsoa(ns_client_t *client, dns_db_t *db, dns_dbversion_t *version,
dns_name_clone(dns_db_origin(db), name);
rdataset = query_newrdataset(client);
if (rdataset == NULL) {
CTRACE(ISC_LOG_ERROR, "unable to allocate rdataset");
eresult = DNS_R_SERVFAIL;
goto cleanup;
}
if (WANTDNSSEC(client) && dns_db_issecure(db)) {
sigrdataset = query_newrdataset(client);
if (sigrdataset == NULL) {
CTRACE(ISC_LOG_ERROR, "unable to allocate sigrdataset");
eresult = DNS_R_SERVFAIL;
goto cleanup;
}
@ -2670,6 +2694,7 @@ query_addsoa(ns_client_t *client, dns_db_t *db, dns_dbversion_t *version,
* This is bad. We tried to get the SOA RR at the zone top
* and it didn't work!
*/
CTRACE(ISC_LOG_ERROR, "unable to find SOA RR at zone apex");
eresult = DNS_R_SERVFAIL;
} else {
/*
@ -2734,7 +2759,7 @@ query_addns(ns_client_t *client, dns_db_t *db, dns_dbversion_t *version) {
dns_clientinfomethods_t cm;
dns_clientinfo_t ci;
CTRACE("query_addns");
CTRACE(ISC_LOG_DEBUG(3), "query_addns");
/*
* Initialization.
*/
@ -2752,21 +2777,24 @@ query_addns(ns_client_t *client, dns_db_t *db, dns_dbversion_t *version) {
*/
result = dns_message_gettempname(client->message, &name);
if (result != ISC_R_SUCCESS) {
CTRACE("query_addns: dns_message_gettempname failed: done");
CTRACE(ISC_LOG_DEBUG(3),
"query_addns: dns_message_gettempname failed: done");
return (result);
}
dns_name_init(name, NULL);
dns_name_clone(dns_db_origin(db), name);
rdataset = query_newrdataset(client);
if (rdataset == NULL) {
CTRACE("query_addns: query_newrdataset failed");
CTRACE(ISC_LOG_ERROR,
"query_addns: query_newrdataset failed");
eresult = DNS_R_SERVFAIL;
goto cleanup;
}
if (WANTDNSSEC(client) && dns_db_issecure(db)) {
sigrdataset = query_newrdataset(client);
if (sigrdataset == NULL) {
CTRACE("query_addns: query_newrdataset failed");
CTRACE(ISC_LOG_ERROR,
"query_addns: query_newrdataset failed");
eresult = DNS_R_SERVFAIL;
goto cleanup;
}
@ -2781,14 +2809,15 @@ query_addns(ns_client_t *client, dns_db_t *db, dns_dbversion_t *version) {
dns_rdatatype_ns, 0, client->now,
rdataset, sigrdataset);
} else {
CTRACE("query_addns: calling dns_db_find");
CTRACE(ISC_LOG_DEBUG(3), "query_addns: calling dns_db_find");
result = dns_db_findext(db, name, NULL, dns_rdatatype_ns,
client->query.dboptions, 0, &node,
fname, &cm, &ci, rdataset, sigrdataset);
CTRACE("query_addns: dns_db_find complete");
CTRACE(ISC_LOG_DEBUG(3), "query_addns: dns_db_find complete");
}
if (result != ISC_R_SUCCESS) {
CTRACE("query_addns: "
CTRACE(ISC_LOG_ERROR,
"query_addns: "
"dns_db_findrdataset or dns_db_find failed");
/*
* This is bad. We tried to get the NS rdataset at the zone
@ -2805,7 +2834,7 @@ query_addns(ns_client_t *client, dns_db_t *db, dns_dbversion_t *version) {
}
cleanup:
CTRACE("query_addns: cleanup");
CTRACE(ISC_LOG_DEBUG(3), "query_addns: cleanup");
query_putrdataset(client, &rdataset);
if (sigrdataset != NULL)
query_putrdataset(client, &sigrdataset);
@ -2814,7 +2843,7 @@ query_addns(ns_client_t *client, dns_db_t *db, dns_dbversion_t *version) {
if (node != NULL)
dns_db_detachnode(db, &node);
CTRACE("query_addns: done");
CTRACE(ISC_LOG_DEBUG(3), "query_addns: done");
return (eresult);
}
@ -3082,7 +3111,7 @@ query_addbestns(ns_client_t *client) {
dns_clientinfomethods_t cm;
dns_clientinfo_t ci;
CTRACE("query_addbestns");
CTRACE(ISC_LOG_DEBUG(3), "query_addbestns");
fname = NULL;
zfname = NULL;
rdataset = NULL;
@ -3287,7 +3316,7 @@ query_addds(ns_client_t *client, dns_db_t *db, dns_dbnode_t *node,
isc_result_t result;
unsigned int count;
CTRACE("query_addds");
CTRACE(ISC_LOG_DEBUG(3), "query_addds");
rname = NULL;
rdataset = NULL;
sigrdataset = NULL;
@ -3417,7 +3446,7 @@ query_addwildcardproof(ns_client_t *client, dns_db_t *db,
dns_clientinfomethods_t cm;
dns_clientinfo_t ci;
CTRACE("query_addwildcardproof");
CTRACE(ISC_LOG_DEBUG(3), "query_addwildcardproof");
fname = NULL;
rdataset = NULL;
sigrdataset = NULL;
@ -3781,9 +3810,10 @@ query_resume(isc_task_t *task, isc_event_t *event) {
if (devent->sigrdataset != NULL)
query_putrdataset(client, &devent->sigrdataset);
isc_event_free(&event);
if (fetch_canceled)
if (fetch_canceled) {
CTRACE(ISC_LOG_ERROR, "fetch cancelled");
query_error(client, DNS_R_SERVFAIL, __LINE__);
else
} else
query_next(client, ISC_R_CANCELED);
/*
* This may destroy the client.
@ -4047,8 +4077,11 @@ rpz_ready(ns_client_t *client, dns_rdataset_t **rdatasetp)
if (*rdatasetp == NULL) {
*rdatasetp = query_newrdataset(client);
if (*rdatasetp == NULL)
if (*rdatasetp == NULL) {
CTRACE(ISC_LOG_ERROR,
"rpz_ready: query_newrdataset failed");
return (DNS_R_SERVFAIL);
}
} else if (dns_rdataset_isassociated(*rdatasetp)) {
dns_rdataset_disassociate(*rdatasetp);
}
@ -4187,6 +4220,7 @@ rpz_rrset_find(ns_client_t *client, dns_name_t *name, dns_rdatatype_t type,
st->r.r_rdataset = NULL;
result = st->r.r_result;
if (result == DNS_R_DELEGATION) {
CTRACE(ISC_LOG_ERROR, "RPZ recursing");
rpz_log_fail(client, DNS_RPZ_ERROR_LEVEL, name,
rpz_type, " rpz_rrset_find(1)", result);
st->m.policy = DNS_RPZ_POLICY_ERROR;
@ -4372,8 +4406,10 @@ rpz_find_p(ns_client_t *client, dns_name_t *self_name, dns_rdatatype_t qtype,
*/
rpz_clean(zonep, dbp, nodep, rdatasetp);
result = rpz_ready(client, rdatasetp);
if (result != ISC_R_SUCCESS)
if (result != ISC_R_SUCCESS) {
CTRACE(ISC_LOG_ERROR, "rpz_ready() failed");
return (DNS_R_SERVFAIL);
}
*versionp = NULL;
result = rpz_getdb(client, p_name, rpz_type, zonep, dbp, versionp);
if (result != ISC_R_SUCCESS)
@ -4396,6 +4432,8 @@ rpz_find_p(ns_client_t *client, dns_name_t *self_name, dns_rdatatype_t qtype,
if (result != ISC_R_SUCCESS) {
rpz_log_fail(client, DNS_RPZ_ERROR_LEVEL, p_name,
rpz_type, " allrdatasets()", result);
CTRACE(ISC_LOG_ERROR,
"rpz_find_p: allrdatasets failed");
return (DNS_R_SERVFAIL);
}
for (result = dns_rdatasetiter_first(rdsiter);
@ -4413,6 +4451,9 @@ rpz_find_p(ns_client_t *client, dns_name_t *self_name, dns_rdatatype_t qtype,
rpz_log_fail(client, DNS_RPZ_ERROR_LEVEL,
p_name, rpz_type,
" rdatasetiter", result);
CTRACE(ISC_LOG_ERROR,
"rpz_find_p: rdatasetiter_destroy "
"failed");
return (DNS_R_SERVFAIL);
}
/*
@ -4467,6 +4508,8 @@ rpz_find_p(ns_client_t *client, dns_name_t *self_name, dns_rdatatype_t qtype,
default:
rpz_log_fail(client, DNS_RPZ_ERROR_LEVEL, p_name, rpz_type,
"", result);
CTRACE(ISC_LOG_ERROR,
"rpz_find_p: unexpected result");
return (DNS_R_SERVFAIL);
}
}
@ -4696,6 +4739,8 @@ rpz_rewrite_ip_rrset(ns_client_t *client,
rpz_type, " NS address rewrite rrset",
result);
}
CTRACE(ISC_LOG_ERROR,
"rpz_rewrite_ip_rrset: unexpected result");
return (DNS_R_SERVFAIL);
}
@ -5330,6 +5375,7 @@ cleanup:
rpz_match_clear(st);
}
if (st->m.policy == DNS_RPZ_POLICY_ERROR) {
CTRACE(ISC_LOG_ERROR, "SERVFAIL due to RPZ policy");
st->m.type = DNS_RPZ_TYPE_BAD;
result = DNS_R_SERVFAIL;
}
@ -5563,7 +5609,7 @@ query_addnoqnameproof(ns_client_t *client, dns_rdataset_t *rdataset) {
dns_rdataset_t *neg, *negsig;
isc_result_t result = ISC_R_NOMEMORY;
CTRACE("query_addnoqnameproof");
CTRACE(ISC_LOG_DEBUG(3), "query_addnoqnameproof");
fname = NULL;
neg = NULL;
@ -5977,7 +6023,7 @@ redirect(ns_client_t *client, dns_name_t *name, dns_rdataset_t *rdataset,
dns_clientinfo_t ci;
ns_dbversion_t *dbversion;
CTRACE("redirect");
CTRACE(ISC_LOG_DEBUG(3), "redirect");
if (client->view->redirect == NULL)
return (ISC_FALSE);
@ -6044,7 +6090,7 @@ redirect(ns_client_t *client, dns_name_t *name, dns_rdataset_t *rdataset,
dns_db_detach(&db);
return (ISC_FALSE);
}
CTRACE("redirect: found data: done");
CTRACE(ISC_LOG_DEBUG(3), "redirect: found data: done");
dns_name_copy(found, name, NULL);
if (dns_rdataset_isassociated(rdataset))
@ -6109,11 +6155,12 @@ query_find(ns_client_t *client, dns_fetchevent_t *event, dns_rdatatype_t qtype)
isc_boolean_t nxrewrite = ISC_FALSE;
dns_clientinfomethods_t cm;
dns_clientinfo_t ci;
char errmsg[256];
isc_boolean_t associated;
dns_section_t section;
dns_ttl_t ttl;
CTRACE("query_find");
CTRACE(ISC_LOG_DEBUG(3), "query_find");
/*
* One-time initialization.
@ -6205,11 +6252,15 @@ query_find(ns_client_t *client, dns_fetchevent_t *event, dns_rdatatype_t qtype)
*/
dbuf = query_getnamebuf(client);
if (dbuf == NULL) {
CTRACE(ISC_LOG_ERROR,
"query_find: query_getnamebuf failed (1)");
QUERY_ERROR(DNS_R_SERVFAIL);
goto cleanup;
}
fname = query_newname(client, dbuf, &b);
if (fname == NULL) {
CTRACE(ISC_LOG_ERROR,
"query_find: query_newname failed (1)");
QUERY_ERROR(DNS_R_SERVFAIL);
goto cleanup;
}
@ -6221,6 +6272,8 @@ query_find(ns_client_t *client, dns_fetchevent_t *event, dns_rdatatype_t qtype)
}
result = dns_name_copy(tname, fname, NULL);
if (result != ISC_R_SUCCESS) {
CTRACE(ISC_LOG_ERROR,
"query_find: dns_name_copy failed");
QUERY_ERROR(DNS_R_SERVFAIL);
goto cleanup;
}
@ -6249,7 +6302,7 @@ query_find(ns_client_t *client, dns_fetchevent_t *event, dns_rdatatype_t qtype)
type = qtype;
restart:
CTRACE("query_find: restart");
CTRACE(ISC_LOG_DEBUG(3), "query_find: restart");
want_restart = ISC_FALSE;
authoritative = ISC_FALSE;
version = NULL;
@ -6326,8 +6379,11 @@ query_find(ns_client_t *client, dns_fetchevent_t *event, dns_rdatatype_t qtype)
inc_stats(client, dns_nsstatscounter_authrej);
if (!PARTIALANSWER(client))
QUERY_ERROR(DNS_R_REFUSED);
} else
} else {
CTRACE(ISC_LOG_ERROR,
"query_find: query_getdb failed");
QUERY_ERROR(DNS_R_SERVFAIL);
}
goto cleanup;
}
@ -6360,24 +6416,30 @@ query_find(ns_client_t *client, dns_fetchevent_t *event, dns_rdatatype_t qtype)
}
db_find:
CTRACE("query_find: db_find");
CTRACE(ISC_LOG_DEBUG(3), "query_find: db_find");
/*
* We'll need some resources...
*/
dbuf = query_getnamebuf(client);
if (dbuf == NULL) {
CTRACE(ISC_LOG_ERROR,
"query_find: query_getnamebuf failed (2)");
QUERY_ERROR(DNS_R_SERVFAIL);
goto cleanup;
}
fname = query_newname(client, dbuf, &b);
rdataset = query_newrdataset(client);
if (fname == NULL || rdataset == NULL) {
CTRACE(ISC_LOG_ERROR,
"query_find: query_newname failed (2)");
QUERY_ERROR(DNS_R_SERVFAIL);
goto cleanup;
}
if (WANTDNSSEC(client) && (!is_zone || dns_db_issecure(db))) {
sigrdataset = query_newrdataset(client);
if (sigrdataset == NULL) {
CTRACE(ISC_LOG_ERROR,
"query_find: query_newrdataset failed (2)");
QUERY_ERROR(DNS_R_SERVFAIL);
goto cleanup;
}
@ -6394,7 +6456,7 @@ query_find(ns_client_t *client, dns_fetchevent_t *event, dns_rdatatype_t qtype)
dns_cache_updatestats(client->view->cache, result);
resume:
CTRACE("query_find: resume");
CTRACE(ISC_LOG_DEBUG(3), "query_find: resume");
/*
* Rate limit these responses to this client.
@ -6759,6 +6821,8 @@ query_find(ns_client_t *client, dns_fetchevent_t *event, dns_rdatatype_t qtype)
goto cleanup;
} else {
/* Unable to give root server referral. */
CTRACE(ISC_LOG_ERROR,
"unable to give root server referral");
QUERY_ERROR(DNS_R_SERVFAIL);
goto cleanup;
}
@ -7025,11 +7089,17 @@ query_find(ns_client_t *client, dns_fetchevent_t *event, dns_rdatatype_t qtype)
if (fname == NULL) {
dbuf = query_getnamebuf(client);
if (dbuf == NULL) {
CTRACE(ISC_LOG_ERROR,
"query_find: "
"query_getnamebuf failed (3)");
QUERY_ERROR(DNS_R_SERVFAIL);
goto cleanup;
}
fname = query_newname(client, dbuf, &b);
if (fname == NULL) {
CTRACE(ISC_LOG_ERROR,
"query_find: "
"query_newname failed (3)");
QUERY_ERROR(DNS_R_SERVFAIL);
goto cleanup;
}
@ -7128,6 +7198,10 @@ query_find(ns_client_t *client, dns_fetchevent_t *event, dns_rdatatype_t qtype)
if (fname == NULL ||
rdataset == NULL ||
sigrdataset == NULL) {
CTRACE(ISC_LOG_ERROR,
"query_find: "
"failure getting "
"closest encloser");
QUERY_ERROR(DNS_R_SERVFAIL);
goto cleanup;
}
@ -7306,11 +7380,17 @@ query_find(ns_client_t *client, dns_fetchevent_t *event, dns_rdatatype_t qtype)
if (fname == NULL) {
dbuf = query_getnamebuf(client);
if (dbuf == NULL) {
CTRACE(ISC_LOG_ERROR,
"query_find: "
"query_getnamebuf failed (4)");
QUERY_ERROR(DNS_R_SERVFAIL);
goto cleanup;
}
fname = query_newname(client, dbuf, &b);
if (fname == NULL) {
CTRACE(ISC_LOG_ERROR,
"query_find: "
"query_newname failed (4)");
QUERY_ERROR(DNS_R_SERVFAIL);
goto cleanup;
}
@ -7567,6 +7647,10 @@ query_find(ns_client_t *client, dns_fetchevent_t *event, dns_rdatatype_t qtype)
/*
* Something has gone wrong.
*/
snprintf(errmsg, sizeof(errmsg) - 1,
"query_find: unexpected error after resuming: %s",
isc_result_totext(result));
CTRACE(ISC_LOG_ERROR, errmsg);
QUERY_ERROR(DNS_R_SERVFAIL);
goto cleanup;
}
@ -7625,6 +7709,8 @@ query_find(ns_client_t *client, dns_fetchevent_t *event, dns_rdatatype_t qtype)
rdsiter = NULL;
result = dns_db_allrdatasets(db, node, version, 0, &rdsiter);
if (result != ISC_R_SUCCESS) {
CTRACE(ISC_LOG_ERROR,
"query_find: type any; allrdatasets failed");
QUERY_ERROR(DNS_R_SERVFAIL);
goto cleanup;
}
@ -7759,12 +7845,18 @@ query_find(ns_client_t *client, dns_fetchevent_t *event, dns_rdatatype_t qtype)
dns_rdatasetiter_destroy(&rdsiter);
fname = query_newname(client, dbuf, &b);
goto nxrrset_rrsig;
} else
} else {
CTRACE(ISC_LOG_ERROR,
"query_find: no matching rdatasets "
"in cache");
result = DNS_R_SERVFAIL;
}
}
dns_rdatasetiter_destroy(&rdsiter);
if (result != ISC_R_NOMORE) {
CTRACE(ISC_LOG_ERROR,
"query_find: dns_rdatasetiter_destroy failed");
QUERY_ERROR(DNS_R_SERVFAIL);
goto cleanup;
}
@ -7988,7 +8080,7 @@ query_find(ns_client_t *client, dns_fetchevent_t *event, dns_rdatatype_t qtype)
}
addauth:
CTRACE("query_find: addauth");
CTRACE(ISC_LOG_DEBUG(3), "query_find: addauth");
/*
* Add NS records to the authority section (if we haven't already
* added them to the answer section).
@ -8016,7 +8108,7 @@ query_find(ns_client_t *client, dns_fetchevent_t *event, dns_rdatatype_t qtype)
dns_fixedname_name(&wildcardname),
ISC_TRUE, ISC_FALSE);
cleanup:
CTRACE("query_find: cleanup");
CTRACE(ISC_LOG_DEBUG(3), "query_find: cleanup");
/*
* General cleanup.
*/
@ -8124,7 +8216,7 @@ query_find(ns_client_t *client, dns_fetchevent_t *event, dns_rdatatype_t qtype)
query_send(client);
ns_client_detach(&client);
}
CTRACE("query_find: done");
CTRACE(ISC_LOG_DEBUG(3), "query_find: done");
return (eresult);
}
@ -8212,7 +8304,7 @@ ns_query_start(ns_client_t *client) {
unsigned int saved_extflags = client->extflags;
unsigned int saved_flags = client->message->flags;
CTRACE("ns_query_start");
CTRACE(ISC_LOG_DEBUG(3), "ns_query_start");
/*
* Test only.

View File

@ -4684,6 +4684,9 @@ directory_callback(const char *clausename, const cfg_obj_t *obj, void *arg) {
static void
scan_interfaces(ns_server_t *server, isc_boolean_t verbose) {
isc_boolean_t match_mapped = server->aclenv.match_mapped;
#ifdef HAVE_GEOIP
isc_boolean_t use_ecs = server->aclenv.geoip_use_ecs;
#endif
ns_interfacemgr_scan(server->interfacemgr, verbose);
/*
@ -4694,6 +4697,9 @@ scan_interfaces(ns_server_t *server, isc_boolean_t verbose) {
ns_interfacemgr_getaclenv(server->interfacemgr));
server->aclenv.match_mapped = match_mapped;
#ifdef HAVE_GEOIP
server->aclenv.geoip_use_ecs = use_ecs;
#endif
}
static isc_result_t
@ -5554,6 +5560,11 @@ load_configuration(const char *filename, ns_server_t *server,
} else
ns_geoip_load(NULL);
ns_g_aclconfctx->geoip = ns_g_geoip;
obj = NULL;
result = ns_config_get(maps, "geoip-use-ecs", &obj);
INSIST(result == ISC_R_SUCCESS);
ns_g_server->aclenv.geoip_use_ecs = cfg_obj_asboolean(obj);
#endif /* HAVE_GEOIP */
/*

View File

@ -242,6 +242,7 @@ init_desc(void) {
"SitNoMatch");
SET_NSSTATDESC(sitmatch, "source identity token - match", "SitMatch");
#endif
SET_NSSTATDESC(ecsopt, "EDNS client subnet option recieved", "ECSOpt");
INSIST(i == dns_nsstatscounter_max);
/* Initialize resolver statistics */

View File

@ -0,0 +1,50 @@
/*
* Copyright (C) 2013 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.
*/
controls { /* empty */ };
options {
query-source address 10.53.0.2;
notify-source 10.53.0.2;
transfer-source 10.53.0.2;
port 5300;
pid-file "named.pid";
listen-on { 10.53.0.2; };
listen-on-v6 { none; };
recursion no;
notify yes;
ixfr-from-differences yes;
check-integrity no;
allow-query-on { 10.53.0.2; };
};
include "../../common/controls.conf";
zone "." {
type hint;
file "../../common/root.hint";
};
zone "example" {
type master;
file "example.db";
};
zone "tsigzone" {
type master;
file "tsigzone.db";
allow-transfer { ecs 10.53/16; !10/8; };
};

View File

@ -0,0 +1,60 @@
/*
* Copyright (C) 2013 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.
*/
controls { /* empty */ };
options {
query-source address 10.53.0.2;
notify-source 10.53.0.2;
transfer-source 10.53.0.2;
port 5300;
pid-file "named.pid";
listen-on { 10.53.0.2; };
listen-on-v6 { none; };
recursion no;
notify yes;
ixfr-from-differences yes;
check-integrity no;
allow-query-on { 10.53.0.2; };
};
include "../../common/controls.conf";
view one {
match-clients { ecs 192.0.2/24; };
zone "." {
type hint;
file "../../common/root.hint";
};
zone "example" {
type master;
file "example.db";
};
};
view two {
zone "." {
type hint;
file "../../common/root.hint";
};
zone "example" {
type master;
file "example.db";
};
};

View File

@ -150,5 +150,35 @@ $DIG +tcp soa example. \
@10.53.0.2 -b 10.53.0.3 -p 5300 > dig.out.${t}
grep "status: NOERROR" dig.out.${t} > /dev/null 2>&1 || { echo "I:test $t failed" ; status=1; }
echo "I:testing EDNS client-subnet ACL processing"
cp -f ns2/named6.conf ns2/named.conf
$RNDC -c ../common/rndc.conf -s 10.53.0.2 -p 9953 reload 2>&1 | sed 's/^/I:ns2 /'
sleep 5
# should fail
t=`expr $t + 1`
$DIG $DIGOPTS tsigzone. \
@10.53.0.2 -b 10.53.0.2 axfr -p 5300 > dig.out.${t}
grep "^;" dig.out.${t} > /dev/null 2>&1 || { echo "I:test $t failed" ; status=1; }
# should succeed
t=`expr $t + 1`
$DIG $DIGOPTS tsigzone. \
@10.53.0.2 -b 10.53.0.2 +subnet="10.53.0/24" axfr -p 5300 > dig.out.${t}
grep "^;" dig.out.${t} > /dev/null 2>&1 && { echo "I:test $t failed" ; status=1; }
echo "I:testing EDNS client-subnet response scope"
cp -f ns2/named7.conf ns2/named.conf
$RNDC -c ../common/rndc.conf -s 10.53.0.2 -p 9953 reload 2>&1 | sed 's/^/I:ns2 /'
sleep 5
t=`expr $t + 1`
$DIG example. soa @10.53.0.2 +subnet="10.53.0.1/32" -p 5300 > dig.out.${t}
grep "CLIENT-SUBNET.*10.53.0.1/32/0" dig.out.${t} > /dev/null || { echo "I:test $t failed" ; status=1; }
t=`expr $t + 1`
$DIG example. soa @10.53.0.2 +subnet="192.0.2.128/32" -p 5300 > dig.out.${t}
grep "CLIENT-SUBNET.*192.0.2.128/32/24" dig.out.${t} > /dev/null || { echo "I:test $t failed" ; status=1; }
echo "I:exit status: $status"
exit $status

View File

@ -15,5 +15,5 @@
# PERFORMANCE OF THIS SOFTWARE.
rm -f ns2/named.conf
rm -f ns2/example[1234567].db
rm -f ns2/example*.db
rm -f dig.out.* rndc.out.*

View File

@ -5,3 +5,4 @@
10.53.0.5/32 CL
10.53.0.6/32 DE
10.53.0.7/32 EH
192.0.2/24 O1

1 10.53.0.1/32 AU
5 10.53.0.5/32 CL
6 10.53.0.6/32 DE
7 10.53.0.7/32 EH
8 192.0.2/24 O1

View File

@ -18,8 +18,8 @@ GeoIPDoain.dat: Domain Name
GeoIPASNum.dat: AS Number
GeoIPNetSpeed.dat: Net Speed
GeoIP.dat can also be generated using the open source 'geoip-csv-to-dat'
utility:
GeoIP.dat can also be egenerated using the open source 'geoip-csv-to-dat'
utility (also known in some packages as "geoip-generator"):
$ geoip-csv-to-dat -i "BIND9 geoip test data v1" -o GeoIP.dat << EOF
"10.53.0.1","10.53.0.1","171245569","171245569","AU","Australia"
@ -29,4 +29,5 @@ $ geoip-csv-to-dat -i "BIND9 geoip test data v1" -o GeoIP.dat << EOF
"10.53.0.5","10.53.0.5","171245573","171245573","CL","Chile"
"10.53.0.6","10.53.0.6","171245574","171245574","DE","Germany"
"10.53.0.7","10.53.0.7","171245575","171245575","EH","Western Sahara"
"192.0.2.0","192.0.2.255","3221225984","3221226239","O1","Other"
EOF

View File

@ -95,6 +95,14 @@ view seven {
};
};
view other {
match-clients { geoip db country country O1; };
zone "example" {
type master;
file "exampleother.db";
};
};
view none {
match-clients { any; };
zone "example" {

View File

@ -1,5 +1,5 @@
/*
* Copyright (C) 2013 Internet Systems Consortium, Inc. ("ISC")
* Copyright (C) 2014 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
@ -40,7 +40,7 @@ controls {
};
view one {
match-clients { geoip domain one.de; };
match-clients { geoip asnum "AS100001"; };
zone "example" {
type master;
file "example1.db";
@ -48,7 +48,7 @@ view one {
};
view two {
match-clients { geoip domain two.com; };
match-clients { geoip asnum "AS100002"; };
zone "example" {
type master;
file "example2.db";
@ -56,7 +56,7 @@ view two {
};
view three {
match-clients { geoip domain three.com; };
match-clients { geoip asnum "AS100003"; };
zone "example" {
type master;
file "example3.db";
@ -64,7 +64,7 @@ view three {
};
view four {
match-clients { geoip domain four.com; };
match-clients { geoip asnum "AS100004"; };
zone "example" {
type master;
file "example4.db";
@ -72,7 +72,7 @@ view four {
};
view five {
match-clients { geoip domain five.es; };
match-clients { geoip asnum "AS100005"; };
zone "example" {
type master;
file "example5.db";
@ -80,7 +80,7 @@ view five {
};
view six {
match-clients { geoip domain six.it; };
match-clients { geoip asnum "AS100006"; };
zone "example" {
type master;
file "example6.db";
@ -88,7 +88,7 @@ view six {
};
view seven {
match-clients { geoip domain seven.org; };
match-clients { geoip asnum "AS100007"; };
zone "example" {
type master;
file "example7.db";

View File

@ -40,7 +40,7 @@ controls {
};
view one {
match-clients { geoip netspeed 0; };
match-clients { geoip domain one.de; };
zone "example" {
type master;
file "example1.db";
@ -48,7 +48,7 @@ view one {
};
view two {
match-clients { geoip netspeed 1; };
match-clients { geoip domain two.com; };
zone "example" {
type master;
file "example2.db";
@ -56,7 +56,7 @@ view two {
};
view three {
match-clients { geoip netspeed 2; };
match-clients { geoip domain three.com; };
zone "example" {
type master;
file "example3.db";
@ -64,13 +64,37 @@ view three {
};
view four {
match-clients { geoip netspeed 3; };
match-clients { geoip domain four.com; };
zone "example" {
type master;
file "example4.db";
};
};
view five {
match-clients { geoip domain five.es; };
zone "example" {
type master;
file "example5.db";
};
};
view six {
match-clients { geoip domain six.it; };
zone "example" {
type master;
file "example6.db";
};
};
view seven {
match-clients { geoip domain seven.org; };
zone "example" {
type master;
file "example7.db";
};
};
view none {
match-clients { any; };
zone "example" {

View File

@ -1,5 +1,5 @@
/*
* Copyright (C) 2014 Internet Systems Consortium, Inc. ("ISC")
* Copyright (C) 2013 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
@ -18,10 +18,6 @@
controls { /* empty */ };
acl blocking {
geoip db country country AU;
};
options {
query-source address 10.53.0.2;
notify-source 10.53.0.2;
@ -32,7 +28,6 @@ options {
listen-on-v6 { none; };
recursion no;
geoip-directory "../data";
blackhole { blocking; };
};
key rndc_key {
@ -43,3 +38,43 @@ key rndc_key {
controls {
inet 10.53.0.2 port 9953 allow { any; } keys { rndc_key; };
};
view one {
match-clients { geoip netspeed 0; };
zone "example" {
type master;
file "example1.db";
};
};
view two {
match-clients { geoip netspeed 1; };
zone "example" {
type master;
file "example2.db";
};
};
view three {
match-clients { geoip netspeed 2; };
zone "example" {
type master;
file "example3.db";
};
};
view four {
match-clients { geoip netspeed 3; };
zone "example" {
type master;
file "example4.db";
};
};
view none {
match-clients { any; };
zone "example" {
type master;
file "example.db.in";
};
};

View File

@ -18,6 +18,10 @@
controls { /* empty */ };
acl blocking {
geoip db country country AU;
};
options {
query-source address 10.53.0.2;
notify-source 10.53.0.2;
@ -28,6 +32,7 @@ options {
listen-on-v6 { none; };
recursion no;
geoip-directory "../data";
blackhole { blocking; };
};
key rndc_key {
@ -38,75 +43,3 @@ key rndc_key {
controls {
inet 10.53.0.2 port 9953 allow { any; } keys { rndc_key; };
};
acl gAU { geoip db country country AU; };
acl gUS { geoip db country country US; };
acl gGB { geoip db country country GB; };
acl gCA { geoip db country country CA; };
acl gCL { geoip db country country CL; };
acl gDE { geoip db country country DE; };
acl gEH { geoip db country country EH; };
view one {
match-clients { gAU; };
zone "example" {
type master;
file "example1.db";
};
};
view two {
match-clients { gUS; };
zone "example" {
type master;
file "example2.db";
};
};
view three {
match-clients { gGB; };
zone "example" {
type master;
file "example3.db";
};
};
view four {
match-clients { gCA; };
zone "example" {
type master;
file "example4.db";
};
};
view five {
match-clients { gCL; };
zone "example" {
type master;
file "example5.db";
};
};
view six {
match-clients { gDE; };
zone "example" {
type master;
file "example6.db";
};
};
view seven {
match-clients { gEH; };
zone "example" {
type master;
file "example7.db";
};
};
view none {
match-clients { any; };
zone "example" {
type master;
file "example.db.in";
};
};

View File

@ -0,0 +1,113 @@
/*
* Copyright (C) 2014 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.
*/
// NS2
controls { /* empty */ };
options {
query-source address 10.53.0.2;
notify-source 10.53.0.2;
transfer-source 10.53.0.2;
port 5300;
pid-file "named.pid";
listen-on { 127.0.0.1; 10.53.0.2; };
listen-on-v6 { none; };
recursion no;
geoip-directory "../data";
geoip-use-ecs no;
};
key rndc_key {
secret "1234abcd8765";
algorithm hmac-sha256;
};
controls {
inet 10.53.0.2 port 9953 allow { any; } keys { rndc_key; };
};
acl gAU { geoip db country country AU; };
acl gUS { geoip db country country US; };
acl gGB { geoip db country country GB; };
acl gCA { geoip db country country CA; };
acl gCL { geoip db country country CL; };
acl gDE { geoip db country country DE; };
acl gEH { geoip db country country EH; };
view one {
match-clients { gAU; };
zone "example" {
type master;
file "example1.db";
};
};
view two {
match-clients { gUS; };
zone "example" {
type master;
file "example2.db";
};
};
view three {
match-clients { gGB; };
zone "example" {
type master;
file "example3.db";
};
};
view four {
match-clients { gCA; };
zone "example" {
type master;
file "example4.db";
};
};
view five {
match-clients { gCL; };
zone "example" {
type master;
file "example5.db";
};
};
view six {
match-clients { gDE; };
zone "example" {
type master;
file "example6.db";
};
};
view seven {
match-clients { gEH; };
zone "example" {
type master;
file "example7.db";
};
};
view none {
match-clients { any; };
zone "example" {
type master;
file "examplebogus.db";
};
};

View File

@ -21,7 +21,7 @@ $SHELL clean.sh
cp ns2/named1.conf ns2/named.conf
for i in 1 2 3 4 5 6 7; do
for i in 1 2 3 4 5 6 7 other bogus; do
cp ns2/example.db.in ns2/example${i}.db
echo "@ IN TXT \"$i\"" >> ns2/example$i.db
done

View File

@ -38,6 +38,30 @@ done
[ $ret -eq 0 ] || echo "I:failed"
status=`expr $status + $ret`
n=`expr $n + 1`
echo "I:checking GeoIP country database by code (using client subnet) ($n)"
ret=0
lret=0
for i in 1 2 3 4 5 6 7; do
$DIG $DIGOPTS txt example -b 127.0.0.1 +subnet="10.53.0.$i/0" > dig.out.ns2.test$n.$i || lret=1
j=`cat dig.out.ns2.test$n.$i | tr -d '"'`
[ "$i" = "$j" ] || lret=1
[ $lret -eq 1 ] && break
done
[ $lret -eq 1 ] && ret=1
[ $ret -eq 0 ] || echo "I:failed"
status=`expr $status + $ret`
n=`expr $n + 1`
echo "I:checking response scope using client subnet ($n)"
ret=0
$DIG +tcp -p5300 @10.53.0.2 txt example -b 127.0.0.1 +subnet="10.53.0.1/32" > dig.out.ns2.test$n.1 || ret=1
grep 'CLIENT-SUBNET.*10.53.0.1/32/32' dig.out.ns2.test$n.1 > /dev/null || ret=1
$DIG +tcp -p5300 @10.53.0.2 txt example -b 127.0.0.1 +subnet="192.0.2.64/32" > dig.out.ns2.test$n.2 || ret=1
grep 'CLIENT-SUBNET.*192.0.2.64/32/24' dig.out.ns2.test$n.2 > /dev/null || ret=1
[ $ret -eq 0 ] || echo "I:failed"
status=`expr $status + $ret`
echo "I:reloading server"
cp -f ns2/named2.conf ns2/named.conf
$RNDC -c ../common/rndc.conf -s 10.53.0.2 -p 9953 reload 2>&1 | sed 's/^/I:ns2 /'
@ -115,6 +139,21 @@ done
[ $ret -eq 0 ] || echo "I:failed"
status=`expr $status + $ret`
n=`expr $n + 1`
echo "I:checking GeoIP region database (using client subnet) ($n)"
ret=0
lret=0
for i in 1 2 3 4 5 6 7; do
$DIG $DIGOPTS txt example -b 127.0.0.1 +subnet="10.53.0.$i/32" > dig.out.ns2.test$n.$i || lret=1
j=`cat dig.out.ns2.test$n.$i | tr -d '"'`
[ "$i" = "$j" ] || lret=1
[ $lret -eq 1 ] && break
done
[ $lret -eq 1 ] && ret=1
[ $ret -eq 0 ] || echo "I:failed"
status=`expr $status + $ret`
echo "I:reloading server"
cp -f ns2/named6.conf ns2/named.conf
$RNDC -c ../common/rndc.conf -s 10.53.0.2 -p 9953 reload 2>&1 | sed 's/^/I:ns2 /'
@ -134,6 +173,20 @@ done
[ $ret -eq 0 ] || echo "I:failed"
status=`expr $status + $ret`
n=`expr $n + 1`
echo "I:checking GeoIP city database (using client subnet) ($n)"
ret=0
lret=0
for i in 1 2 3 4 5 6 7; do
$DIG $DIGOPTS txt example -b 127.0.0.1 +subnet="10.53.0.$i/32" > dig.out.ns2.test$n.$i || lret=1
j=`cat dig.out.ns2.test$n.$i | tr -d '"'`
[ "$i" = "$j" ] || lret=1
[ $lret -eq 1 ] && break
done
[ $lret -eq 1 ] && ret=1
[ $ret -eq 0 ] || echo "I:failed"
status=`expr $status + $ret`
echo "I:reloading server"
cp -f ns2/named7.conf ns2/named.conf
$RNDC -c ../common/rndc.conf -s 10.53.0.2 -p 9953 reload 2>&1 | sed 's/^/I:ns2 /'
@ -153,6 +206,20 @@ done
[ $ret -eq 0 ] || echo "I:failed"
status=`expr $status + $ret`
n=`expr $n + 1`
echo "I:checking GeoIP isp database (using client subnet) ($n)"
ret=0
lret=0
for i in 1 2 3 4 5 6 7; do
$DIG $DIGOPTS txt example -b 127.0.0.1 +subnet="10.53.0.$i/32" > dig.out.ns2.test$n.$i || lret=1
j=`cat dig.out.ns2.test$n.$i | tr -d '"'`
[ "$i" = "$j" ] || lret=1
[ $lret -eq 1 ] && break
done
[ $lret -eq 1 ] && ret=1
[ $ret -eq 0 ] || echo "I:failed"
status=`expr $status + $ret`
echo "I:reloading server"
cp -f ns2/named8.conf ns2/named.conf
$RNDC -c ../common/rndc.conf -s 10.53.0.2 -p 9953 reload 2>&1 | sed 's/^/I:ns2 /'
@ -172,6 +239,20 @@ done
[ $ret -eq 0 ] || echo "I:failed"
status=`expr $status + $ret`
n=`expr $n + 1`
echo "I:checking GeoIP org database (using client subnet) ($n)"
ret=0
lret=0
for i in 1 2 3 4 5 6 7; do
$DIG $DIGOPTS txt example -b 127.0.0.1 +subnet="10.53.0.$i/32" > dig.out.ns2.test$n.$i || lret=1
j=`cat dig.out.ns2.test$n.$i | tr -d '"'`
[ "$i" = "$j" ] || lret=1
[ $lret -eq 1 ] && break
done
[ $lret -eq 1 ] && ret=1
[ $ret -eq 0 ] || echo "I:failed"
status=`expr $status + $ret`
echo "I:reloading server"
cp -f ns2/named9.conf ns2/named.conf
$RNDC -c ../common/rndc.conf -s 10.53.0.2 -p 9953 reload 2>&1 | sed 's/^/I:ns2 /'
@ -191,11 +272,58 @@ done
[ $ret -eq 0 ] || echo "I:failed"
status=`expr $status + $ret`
n=`expr $n + 1`
echo "I:checking GeoIP asnum database (using client subnet) ($n)"
ret=0
lret=0
for i in 1 2 3 4 5 6 7; do
$DIG $DIGOPTS txt example -b 127.0.0.1 +subnet="10.53.0.$i/32" > dig.out.ns2.test$n.$i || lret=1
j=`cat dig.out.ns2.test$n.$i | tr -d '"'`
[ "$i" = "$j" ] || lret=1
[ $lret -eq 1 ] && break
done
[ $lret -eq 1 ] && ret=1
[ $ret -eq 0 ] || echo "I:failed"
status=`expr $status + $ret`
echo "I:reloading server"
cp -f ns2/named10.conf ns2/named.conf
$RNDC -c ../common/rndc.conf -s 10.53.0.2 -p 9953 reload 2>&1 | sed 's/^/I:ns2 /'
sleep 3
n=`expr $n + 1`
echo "I:checking GeoIP asnum database - ASNNNN only ($n)"
ret=0
lret=0
for i in 1 2 3 4 5 6 7; do
$DIG $DIGOPTS txt example -b 10.53.0.$i > dig.out.ns2.test$n.$i || lret=1
j=`cat dig.out.ns2.test$n.$i | tr -d '"'`
[ "$i" = "$j" ] || lret=1
[ $lret -eq 1 ] && break
done
[ $lret -eq 1 ] && ret=1
[ $ret -eq 0 ] || echo "I:failed"
status=`expr $status + $ret`
n=`expr $n + 1`
echo "I:checking GeoIP domain database (using client subnet) ($n)"
ret=0
lret=0
for i in 1 2 3 4 5 6 7; do
$DIG $DIGOPTS txt example -b 127.0.0.1 +subnet="10.53.0.$i/32" > dig.out.ns2.test$n.$i || lret=1
j=`cat dig.out.ns2.test$n.$i | tr -d '"'`
[ "$i" = "$j" ] || lret=1
[ $lret -eq 1 ] && break
done
[ $lret -eq 1 ] && ret=1
[ $ret -eq 0 ] || echo "I:failed"
status=`expr $status + $ret`
echo "I:reloading server"
cp -f ns2/named11.conf ns2/named.conf
$RNDC -c ../common/rndc.conf -s 10.53.0.2 -p 9953 reload 2>&1 | sed 's/^/I:ns2 /'
sleep 3
n=`expr $n + 1`
echo "I:checking GeoIP domain database ($n)"
ret=0
@ -211,7 +339,7 @@ done
status=`expr $status + $ret`
echo "I:reloading server"
cp -f ns2/named11.conf ns2/named.conf
cp -f ns2/named12.conf ns2/named.conf
$RNDC -c ../common/rndc.conf -s 10.53.0.2 -p 9953 reload 2>&1 | sed 's/^/I:ns2 /'
sleep 3
@ -229,8 +357,22 @@ done
[ $ret -eq 0 ] || echo "I:failed"
status=`expr $status + $ret`
n=`expr $n + 1`
echo "I:checking GeoIP netspeed database (using client subnet) ($n)"
ret=0
lret=0
for i in 1 2 3 4; do
$DIG $DIGOPTS txt example -b 127.0.0.1 +subnet="10.53.0.$i/32" > dig.out.ns2.test$n.$i || lret=1
j=`cat dig.out.ns2.test$n.$i | tr -d '"'`
[ "$i" = "$j" ] || lret=1
[ $lret -eq 1 ] && break
done
[ $lret -eq 1 ] && ret=1
[ $ret -eq 0 ] || echo "I:failed"
status=`expr $status + $ret`
echo "I:reloading server"
cp -f ns2/named12.conf ns2/named.conf
cp -f ns2/named13.conf ns2/named.conf
$RNDC -c ../common/rndc.conf -s 10.53.0.2 -p 9953 reload 2>&1 | sed 's/^/I:ns2 /'
sleep 3
@ -243,7 +385,7 @@ $RNDC -c ../common/rndc.conf -s 10.53.0.2 -p 9953 status 2>&1 > rndc.out.ns2.tes
status=`expr $status + $ret`
echo "I:reloading server"
cp -f ns2/named13.conf ns2/named.conf
cp -f ns2/named14.conf ns2/named.conf
$RNDC -c ../common/rndc.conf -s 10.53.0.2 -p 9953 reload 2>&1 | sed 's/^/I:ns2 /'
sleep 3
@ -261,5 +403,29 @@ done
[ $ret -eq 0 ] || echo "I:failed"
status=`expr $status + $ret`
echo "I:reloading server"
cp -f ns2/named14.conf ns2/named.conf
$RNDC -c ../common/rndc.conf -s 10.53.0.2 -p 9953 reload 2>&1 | sed 's/^/I:ns2 /'
sleep 3
n=`expr $n + 1`
echo "I:checking geoip-use-ecs ($n)"
ret=0
lret=0
for i in 1 2 3 4 5 6 7; do
$DIG $DIGOPTS txt example -b 10.53.0.$i > dig.out.ns2.test$n.$i || lret=1
j=`cat dig.out.ns2.test$n.$i | tr -d '"'`
[ "$i" = "$j" ] || lret=1
[ $lret -eq 1 ] && break
$DIG $DIGOPTS txt example -b 127.0.0.1 +subnet="10.53.0.$i/32" > dig.out.ns2.test$n.ecs.$i || lret=1
j=`cat dig.out.ns2.test$n.ecs.$i | tr -d '"'`
[ "$j" = "bogus" ] || lret=1
[ $lret -eq 1 ] && break
done
[ $lret -eq 1 ] && ret=1
[ $ret -eq 0 ] || echo "I:failed"
status=`expr $status + $ret`
echo "I:exit status: $status"
exit $status

View File

@ -0,0 +1,3 @@
options {
sit-secret "012345678901234567890123456789012345678901234567890123456789012";
};

View File

@ -0,0 +1,3 @@
options {
sit-secret "01234567890123456789012345678901234567890123456789012345678901234567890";
};

View File

@ -32,6 +32,15 @@ havetc() {
grep 'flags:.* tc[^;]*;' $1 > /dev/null
}
for bad in bad*.conf
do
ret=0
echo "I:checking that named-checkconf detects error in $bad"
$CHECKCONF $bad > /dev/null 2>&1
if [ $? != 1 ]; then echo "I:failed"; ret=1; fi
status=`expr $status + $ret`
done
n=`expr $n + 1`
echo "I:checking SIT token returned to empty SIT option ($n)"
ret=0

View File

@ -2564,10 +2564,10 @@ $ORIGIN 0.0.0.0.0.0.0.0.8.b.d.0.1.0.0.2.ip6.arpa.
<command>lwres</command> statement in <filename>named.conf</filename>.
</para>
<para>
The number of client queries that the <command>lwresd</command>
daemon is able to serve can be set using the
<option>lwres-tasks</option> and <option>lwres-clients</option>
statements in the configuration.
The number of client queries that the <command>lwresd</command>
daemon is able to serve can be set using the
<option>lwres-tasks</option> and <option>lwres-clients</option>
statements in the configuration.
</para>
</sect1>
</chapter>
@ -3444,63 +3444,6 @@ $ORIGIN 0.0.0.0.0.0.0.0.8.b.d.0.1.0.0.2.ip6.arpa.
</tbody>
</tgroup>
</informaltable>
<para>
When <acronym>BIND</acronym> 9 is built with GeoIP support,
ACLs can also be used for geographic access restrictions.
This is done by specifying an ACL element of the form:
<command>geoip <optional>db <replaceable>database</replaceable></optional> <replaceable>field</replaceable> <replaceable>value</replaceable></command>
</para>
<para>
The <replaceable>field</replaceable> indicates which field
to search for a match. Available fields are "country",
"region", "city", "continent", "postal" (postal code),
"metro" (metro code), "area" (area code), "tz" (timezone),
"isp", "org", "asnum", "domain" and "netspeed".
</para>
<para>
<replaceable>value</replaceable> is the value to searched for
within the database. A string may be quoted if it contains
spaces or other special characters. If this is a "country"
search and the string is two characters long, then it must be a
standard ISO-3166-1 two-letter country code, and if it is three
characters long then it must be an ISO-3166-1 three-letter
country code; otherwise it is the full name of the country.
Similarly, if this is a "region" search and the string is
two characters long, then it must be a standard two-letter state
or province abbreviation; otherwise it is the full name of the
state or province.
</para>
<para>
The <replaceable>database</replaceable> field indicates which
GeoIP database to search for a match. In most cases this is
unnecessary, because most search fields can only be found in
a single database. However, searches for country can be
answered from the "city", "region", or "country" databases,
and searches for region (i.e., state or province) can be
answered from the "city" or "region" databases. For these
search types, specifying a <replaceable>database</replaceable>
will force the query to be answered from that database and no
other. If <replaceable>database</replaceable> is not
specified, then these queries will be answered from the "city",
database if it is installed, or the "region" database if it is
installed, or the "country" database, in that order.
</para>
<para>
Some example GeoIP ACLs:
</para>
<programlisting>geoip country US;
geoip country JAP;
geoip db country country Canada;
geoip db region region WA;
geoip city "San Francisco";
geoip region Oklahoma;
geoip postal 95062;
geoip tz "America/Los_Angeles";
geoip org "Internet Systems Consortium";
</programlisting>
</sect2>
<sect2>
<title><command>controls</command> Statement Grammar</title>
@ -4718,32 +4661,32 @@ badresp:1,adberr:0,findfail:0,valfail:0]
minimum
number of dots in a relative domain name that should result in an
exact match lookup before search path elements are appended.
</para>
<para>
The <option>lwres-tasks</option> statement specifies the number
of worker threads the lightweight resolver will dedicate to serving
clients. By default the number is the same as the number of CPUs on
the system; this can be overridden using the <option>-n</option>
command line option when starting the server.
</para>
<para>
The <option>lwres-clients</option> specifies
the number of client objects per thread the lightweight
resolver should create to serve client queries.
By default, if the lightweight resolver runs as a part
of <command>named</command>, 256 client objects are
created for each task; if it runs as <command>lwresd</command>,
1024 client objects are created for each thread. The maximum
value is 32768; higher values will be silently ignored and
the maximum will be used instead.
Note that setting too high a value may overconsume
system resources.
</para>
<para>
The maximum number of client queries that the lightweight
resolver can handle at any one time equals
<option>lwres-tasks</option> times <option>lwres-clients</option>.
</para>
</para>
<para>
The <option>lwres-tasks</option> statement specifies the number
of worker threads the lightweight resolver will dedicate to serving
clients. By default the number is the same as the number of CPUs on
the system; this can be overridden using the <option>-n</option>
command line option when starting the server.
</para>
<para>
The <option>lwres-clients</option> specifies
the number of client objects per thread the lightweight
resolver should create to serve client queries.
By default, if the lightweight resolver runs as a part
of <command>named</command>, 256 client objects are
created for each task; if it runs as <command>lwresd</command>,
1024 client objects are created for each thread. The maximum
value is 32768; higher values will be silently ignored and
the maximum will be used instead.
Note that setting too high a value may overconsume
system resources.
</para>
<para>
The maximum number of client queries that the lightweight
resolver can handle at any one time equals
<option>lwres-tasks</option> times <option>lwres-clients</option>.
</para>
</sect2>
<sect2>
<title><command>masters</command> Statement Grammar</title>
@ -4855,6 +4798,7 @@ badresp:1,adberr:0,findfail:0,valfail:0]
<optional> allow-update { <replaceable>address_match_list</replaceable> }; </optional>
<optional> allow-update-forwarding { <replaceable>address_match_list</replaceable> }; </optional>
<optional> automatic-interface-scan { <replaceable>yes_or_no</replaceable> }; </optional>
<optional> geoip-use-ecs <replaceable>yes_or_no</replaceable>;</optional>
<optional> update-check-ksk <replaceable>yes_or_no</replaceable>; </optional>
<optional> dnssec-update-mode ( <replaceable>maintain</replaceable> | <replaceable>no-resign</replaceable> ); </optional>
<optional> dnssec-dnskey-kskonly <replaceable>yes_or_no</replaceable>; </optional>
@ -5793,7 +5737,7 @@ options {
For convenience, TTL-style time unit suffixes can be
used to specify the NTA lifetime in seconds, minutes
or hours. <option>nta-lifetime</option> defaults to
one hour. It cannot exceed one day.
one hour. It cannot exceed one day.
</para>
</listitem>
</varlistentry>
@ -5802,31 +5746,31 @@ options {
<term><command>nta-recheck</command></term>
<listitem>
<para>
Species how often to check whether negative
trust anchors added via <command>rndc nta</command>
are still necessary.
Species how often to check whether negative
trust anchors added via <command>rndc nta</command>
are still necessary.
</para>
<para>
A negative trust anchor is normally used when a
domain has stopped validating due to operator error;
it temporarily disables DNSSEC validation for that
domain. In the interest of ensuring that DNSSEC
validation is turned back on as soon as possible,
<command>named</command> will periodically send a
query to the domain, ignoring negative trust anchors,
to find out whether it can now be validated. If so,
the negative trust anchor is allowed to expire early.
A negative trust anchor is normally used when a
domain has stopped validating due to operator error;
it temporarily disables DNSSEC validation for that
domain. In the interest of ensuring that DNSSEC
validation is turned back on as soon as possible,
<command>named</command> will periodically send a
query to the domain, ignoring negative trust anchors,
to find out whether it can now be validated. If so,
the negative trust anchor is allowed to expire early.
</para>
<para>
Validity checks can be disabled for an individual
NTA by using <command>rndc nta -f</command>, or
for all NTA's by setting <option>nta-recheck</option>
to zero.
Validity checks can be disabled for an individual
NTA by using <command>rndc nta -f</command>, or
for all NTA's by setting <option>nta-recheck</option>
to zero.
</para>
<para>
For convenience, TTL-style time unit suffixes can be
used to specify the NTA recheck interval in seconds,
minutes or hours. The default is five minutes.
used to specify the NTA recheck interval in seconds,
minutes or hours. The default is five minutes.
</para>
</listitem>
</varlistentry>
@ -6237,6 +6181,20 @@ options {
</listitem>
</varlistentry>
<varlistentry>
<term><command>geoip-use-ecs</command></term>
<listitem>
<para>
When BIND is compiled with GeoIP support and configured
with "geoip" ACL elements, this option indicates whether
the EDNS Client Subnet option, if present in a request,
should be used for matching against the GeoIP database.
The default is
<command>geoip-use-ecs</command> <userinput>yes</userinput>.
</para>
</listitem>
</varlistentry>
<varlistentry>
<term><command>has-old-clients</command></term>
<listitem>
@ -6421,12 +6379,16 @@ options {
</varlistentry>
<varlistentry>
<term><command>sit-secret</command></term> <listitem>
<term><command>sit-secret</command></term>
<listitem>
<para>
If set, this is a shared secret used for generating
and verifying Source Identity Token EDNS options
within a anycast cluster. If not set the system
will generate a random secret at startup.
will generate a random secret at startup. The
shared secret is encoded as a hex string and needs
to be 128 bits for AES128, 160 bits for SHA1 and
256 bits for SHA256.
</para>
</listitem>
</varlistentry>
@ -9016,24 +8978,24 @@ avoid-v6-udp-ports { 40000; range 50000 60000; };
<varlistentry>
<term><command>masterfile-style</command></term>
<listitem>
<para>
Specifies the formatting of zone files during dump
when the <option>masterfile-format</option> is
<constant>text</constant>. (This option is ignored
with any other <option>masterfile-format</option>.)
</para>
<para>
When set to <constant>relative</constant>,
records are printed in a multi-line format with owner
names expressed relative to a shared origin. When set
to <constant>full</constant>, records are printed in
a single-line format with absolute owner names.
The <constant>full</constant> format is most suitable
when a zone file needs to be processed automatically
by a script. The <constant>relative</constant> format
is more human-readable, and is thus suitable when a
zone is to be edited by hand. The default is
<constant>relative</constant>.
<para>
Specifies the formatting of zone files during dump
when the <option>masterfile-format</option> is
<constant>text</constant>. (This option is ignored
with any other <option>masterfile-format</option>.)
</para>
<para>
When set to <constant>relative</constant>,
records are printed in a multi-line format with owner
names expressed relative to a shared origin. When set
to <constant>full</constant>, records are printed in
a single-line format with absolute owner names.
The <constant>full</constant> format is most suitable
when a zone file needs to be processed automatically
by a script. The <constant>relative</constant> format
is more human-readable, and is thus suitable when a
zone is to be edited by hand. The default is
<constant>relative</constant>.
</para>
</listitem>
</varlistentry>
@ -9046,8 +9008,8 @@ avoid-v6-udp-ports { 40000; range 50000 60000; };
initial value (minimum) and maximum number of recursive
simultaneous clients for any given query
(&lt;qname,qtype,qclass&gt;) that the server will accept
before dropping additional clients.
<command>named</command> will attempt to
before dropping additional clients.
<command>named</command> will attempt to
self tune this value and changes will be logged. The
default values are 10 and 100.
</para>
@ -10560,15 +10522,15 @@ rate-limit {
<para>
The <command>request-expire</command> clause determines
whether the local server, when acting as a slave, will
request the EDNS EXPIRE value. The EDNS EXPIRE value
indicates the remaining time before the zone data will
expire and need to be be refreshed. This is used
when a secondary server transfers a zone from another
secondary server; when transferring from the primary, the
expiration timer is set from the EXPIRE field of the SOA
record instead.
The default is <command>yes</command>.
whether the local server, when acting as a slave, will
request the EDNS EXPIRE value. The EDNS EXPIRE value
indicates the remaining time before the zone data will
expire and need to be be refreshed. This is used
when a secondary server transfers a zone from another
secondary server; when transferring from the primary, the
expiration timer is set from the EXPIRE field of the SOA
record instead.
The default is <command>yes</command>.
</para>
<para>
@ -12455,11 +12417,11 @@ example.com. NS ns2.example.net.
<para>
When set to
<command>serial-update-method date;</command>, the
new SOA serial number will be the current date
in the form "YYYYMMDD", followed by two zeroes,
unless the existing serial number is already greater
than or equal to that value, in which case it is
incremented by one.
new SOA serial number will be the current date
in the form "YYYYMMDD", followed by two zeroes,
unless the existing serial number is already greater
than or equal to that value, in which case it is
incremented by one.
</para>
</listitem>
</varlistentry>
@ -16181,11 +16143,11 @@ HOST-127.EXAMPLE. MX 0 .
<title>Access Control Lists</title>
<para>
Access Control Lists (ACLs) are address match lists that
you can set up and nickname for future use in <command>allow-notify</command>,
<command>allow-query</command>, <command>allow-query-on</command>,
<command>allow-recursion</command>, <command>allow-recursion-on</command>,
you can set up and nickname for future use in
<command>allow-notify</command>, <command>allow-query</command>,
<command>allow-query-on</command>, <command>allow-recursion</command>,
<command>blackhole</command>, <command>allow-transfer</command>,
etc.
<command>match-clients</command>, etc.
</para>
<para>
Using ACLs allows you to have finer control over who can access
@ -16195,11 +16157,19 @@ HOST-127.EXAMPLE. MX 0 .
<para>
It is a <emphasis>good idea</emphasis> to use ACLs, and to
control access to your server. Limiting access to your server by
outside parties can help prevent spoofing and denial of service (DoS) attacks against
your server.
outside parties can help prevent spoofing and denial of service
(DoS) attacks against your server.
</para>
<para>
Here is an example of how to properly apply ACLs:
ACLs match clients on the basis of up to three characteristics:
1) The client's IP address; 2) the TSIG or SIG(0) key that was
used to sign the request, if any; and 3) an address prefix
encoded in an EDNS Client Subnet option, if any.
</para>
<para>
ACLs
<para>
Here is an example of ACLs based on client addresses:
</para>
<programlisting>
@ -16232,10 +16202,137 @@ zone "example.com" {
</programlisting>
<para>
This allows recursive queries of the server from the outside
unless recursion has been previously disabled.
This allows authoritative queries for "example.com" from any
address, but recursive queries only from the networks specified
in "our-nets", and no queries at all from the networks
specified in "bogusnets".
</para>
<para>
In addition to network addresses and prefixes, which are
matched against the source address of the DNS request, ACLs
may include <option>key</option> elements, which specify the
name of a TSIG or SIG(0) key, or <option>ecs</option>
elements, which specify a network prefix but are only matched
if that prefix matches an EDNS client subnet option included
in the request.
</para>
<para>
The EDNS Client Subnet (ECS) option is used by a recursive
resolver to inform an authoritative name server of the network
address block from which the original query was received, enabling
authoritative servers to give different answers to the same
resolver for different resolver clients. An ACL containing
an element of the form
<command>ecs <replaceable>prefix</replaceable></command>
will match if a request arrives in containing an ECS option
encoding an address within that prefix. If the request has no
ECS option, then "ecs" elements are simply ignored. Addresses
in ACLs that are not prefixed with "ecs" are matched only
against the source address.
</para>
<para>
When <acronym>BIND</acronym> 9 is built with GeoIP support,
ACLs can also be used for geographic access restrictions.
This is done by specifying an ACL element of the form:
<command>geoip <optional>db <replaceable>database</replaceable></optional> <replaceable>field</replaceable> <replaceable>value</replaceable></command>
</para>
<para>
The <replaceable>field</replaceable> indicates which field
to search for a match. Available fields are "country",
"region", "city", "continent", "postal" (postal code),
"metro" (metro code), "area" (area code), "tz" (timezone),
"isp", "org", "asnum", "domain" and "netspeed".
</para>
<para>
<replaceable>value</replaceable> is the value to search
for within the database. A string may be quoted if it
contains spaces or other special characters. If this is
an "asnum" search, then the leading "ASNNNN" string can be
used, otherwise the full description must be used (e.g.
"ASNNNN Example Company Name"). If this is a "country"
search and the string is two characters long, then it must
be a standard ISO-3166-1 two-letter country code, and if it
is three characters long then it must be an ISO-3166-1
three-letter country code; otherwise it is the full name
of the country. Similarly, if this is a "region" search
and the string is two characters long, then it must be a
standard two-letter state or province abbreviation;
otherwise it is the full name of the state or province.
</para>
<para>
The <replaceable>database</replaceable> field indicates which
GeoIP database to search for a match. In most cases this is
unnecessary, because most search fields can only be found in
a single database. However, searches for country can be
answered from the "city", "region", or "country" databases,
and searches for region (i.e., state or province) can be
answered from the "city" or "region" databases. For these
search types, specifying a <replaceable>database</replaceable>
will force the query to be answered from that database and no
other. If <replaceable>database</replaceable> is not
specified, then these queries will be answered from the "city",
database if it is installed, or the "region" database if it is
installed, or the "country" database, in that order.
</para>
<para>
By default, if a DNS query includes an EDNS Client Subnet (ECS)
option which encodes a non-zero address prefix, then GeoIP ACLs
will be matched against that address prefix. Otherwise, they
are matched against the source address of the query. To
prevent GeoIP ACLs from matching against ECS options, set
the <command>geoip-use-ecs</option> to <literal>no</literal>.
</para>
<para>
Some example GeoIP ACLs:
</para>
<programlisting>geoip country US;
geoip country JAP;
geoip db country country Canada;
geoip db region region WA;
geoip city "San Francisco";
geoip region Oklahoma;
geoip postal 95062;
geoip tz "America/Los_Angeles";
geoip org "Internet Systems Consortium";
</programlisting>
<para>
ACLs use a "first-match" logic rather than "best-match":
if an address prefix matches an ACL element, then that ACL
is considered to have matched even if a later element would
have matched more specifically. For example, the ACL
<command> { 10/8; !10.0.0.1; }</command> would actually
match a query from 10.0.0.1, because the first element
indicated that the query should be accepted, and the second
element is ignored.
</para>
<para>
When using "nested" ACLs (that is, ACLs included or referenced
within other ACLs), a negative match of a nested ACL will
the containing ACL to continue looking for matches. This
enables complex ACLs to be constructed, in which multiple
client characteristics can be checked at the same time. For
example, to construct an ACL which allows queries only when
it originates from a particular network <emphasis>and</emphasis>
only when it is signed with a particular key, use:
</para>
<programlisting>
allow-query { !{ !10/8; any; }; key example; };
</programlisting>
<para>
Within the nested ACL, any address that is
<emphasis>not</emphasis> in the 10/8 network prefix will
be rejected, and this will terminate processing of the
ACL. Any address that <emphasis>is</emphasis> in the 10/8
network prefix will be accepted, but this causes a negative
match of the nested ACL, so the containing ACL continues
processing. The query will then be accepted if it is signed
by the key "example", and rejected otherwise. The ACL, then,
will only matches when <emphasis>both</emphasis> conditions
are true.
</para>
</sect1>
<sect1>
<title><command>Chroot</command> and <command>Setuid</command></title>
<para>

View File

@ -24,10 +24,12 @@
#include <isc/base64.h>
#include <isc/buffer.h>
#include <isc/file.h>
#include <isc/hex.h>
#include <isc/log.h>
#include <isc/mem.h>
#include <isc/netaddr.h>
#include <isc/parseint.h>
#include <isc/platform.h>
#include <isc/region.h>
#include <isc/result.h>
#include <isc/sockaddr.h>
@ -35,6 +37,18 @@
#include <isc/symtab.h>
#include <isc/util.h>
#ifdef ISC_PLATFORM_USESIT
#ifdef AES_SIT
#include <isc/aes.h>
#endif
#ifdef HMAC_SHA1_SIT
#include <isc/sha1.h>
#endif
#ifdef HMAC_SHA256_SIT
#include <isc/sha2.h>
#endif
#endif
#include <dns/acl.h>
#include <dns/fixedname.h>
#include <dns/rdataclass.h>
@ -1186,6 +1200,52 @@ check_options(const cfg_obj_t *options, isc_log_t *logctx, isc_mem_t *mctx,
"(%d seconds)", recheck, lifetime);
}
#ifdef ISC_PLATFORM_USESIT
obj = NULL;
(void) cfg_map_get(options, "sit-secret", &obj);
if (obj != NULL) {
isc_buffer_t b;
unsigned char secret[32];
memset(secret, 0, sizeof(secret));
isc_buffer_init(&b, secret, sizeof(secret));
tresult = isc_hex_decodestring(cfg_obj_asstring(obj), &b);
if (tresult == ISC_R_NOSPACE) {
cfg_obj_log(obj, logctx, ISC_LOG_ERROR,
"sit-secret: too long");
} else if (tresult != ISC_R_SUCCESS) {
cfg_obj_log(obj, logctx, ISC_LOG_ERROR,
"sit-secret: invalid hex string");
}
if (tresult != ISC_R_SUCCESS)
result = tresult;
#ifdef AES_SIT
if (tresult == ISC_R_SUCCESS &&
isc_buffer_usedlength(&b) != ISC_AES128_KEYLENGTH) {
cfg_obj_log(obj, logctx, ISC_LOG_ERROR,
"AES sit-secret must be on 128 bits");
result = ISC_R_RANGE;
}
#endif
#ifdef HMAC_SHA1_SIT
if (tresult == ISC_R_SUCCESS &&
isc_buffer_usedlength(&b) != ISC_SHA1_DIGESTLENGTH) {
cfg_obj_log(obj, logctx, ISC_LOG_ERROR,
"SHA1 sit-secret must be on 160 bits");
result = ISC_R_RANGE;
}
#endif
#ifdef HMAC_SHA256_SIT
if (tresult == ISC_R_SUCCESS &&
isc_buffer_usedlength(&b) != ISC_SHA256_DIGESTLENGTH) {
cfg_obj_log(obj, logctx, ISC_LOG_ERROR,
"SHA256 sit-secret must be on 256 bits");
result = ISC_R_RANGE;
}
#endif
}
#endif
return (result);
}

View File

@ -15,8 +15,6 @@
* PERFORMANCE OF THIS SOFTWARE.
*/
/* $Id: acl.c,v 1.55 2011/06/17 23:47:49 tbox Exp $ */
/*! \file */
#include <config.h>
@ -194,10 +192,25 @@ dns_acl_match(const isc_netaddr_t *reqaddr,
int *match,
const dns_aclelement_t **matchelt)
{
isc_uint16_t bitlen, family;
return (dns_acl_match2(reqaddr, reqsigner, NULL, 0, NULL, acl, env,
match, matchelt));
}
isc_result_t
dns_acl_match2(const isc_netaddr_t *reqaddr,
const dns_name_t *reqsigner,
const isc_netaddr_t *ecs,
isc_uint8_t ecslen,
isc_uint8_t *scope,
const dns_acl_t *acl,
const dns_aclenv_t *env,
int *match,
const dns_aclelement_t **matchelt)
{
isc_uint16_t bitlen;
isc_prefix_t pfx;
isc_radix_node_t *node = NULL;
const isc_netaddr_t *addr;
const isc_netaddr_t *addr = reqaddr;
isc_netaddr_t v4addr;
isc_result_t result;
int match_num = -1;
@ -205,20 +218,19 @@ dns_acl_match(const isc_netaddr_t *reqaddr,
REQUIRE(reqaddr != NULL);
REQUIRE(matchelt == NULL || *matchelt == NULL);
REQUIRE(ecs != NULL || scope == NULL);
if (env == NULL || env->match_mapped == ISC_FALSE ||
reqaddr->family != AF_INET6 ||
!IN6_IS_ADDR_V4MAPPED(&reqaddr->type.in6))
addr = reqaddr;
else {
isc_netaddr_fromv4mapped(&v4addr, reqaddr);
if (env != NULL && env->match_mapped &&
addr->family == AF_INET6 &&
IN6_IS_ADDR_V4MAPPED(&addr->type.in6))
{
isc_netaddr_fromv4mapped(&v4addr, addr);
addr = &v4addr;
}
/* Always match with host addresses. */
family = addr->family;
bitlen = family == AF_INET6 ? 128 : 32;
NETADDR_TO_PREFIX_T(addr, pfx, bitlen);
bitlen = (addr->family == AF_INET6) ? 128 : 32;
NETADDR_TO_PREFIX_T(addr, pfx, bitlen, ISC_FALSE);
/* Assume no match. */
*match = 0;
@ -228,37 +240,75 @@ dns_acl_match(const isc_netaddr_t *reqaddr,
/* Found a match. */
if (result == ISC_R_SUCCESS && node != NULL) {
match_num = node->node_num[ISC_IS6(family)];
if (*(isc_boolean_t *) node->data[ISC_IS6(family)] == ISC_TRUE)
int off = ISC_RADIX_OFF(&pfx);
match_num = node->node_num[off];
if (*(isc_boolean_t *) node->data[off])
*match = match_num;
else
*match = -match_num;
}
isc_refcount_destroy(&pfx.refcount);
/*
* If ecs is not NULL, we search the radix tree again to
* see if we find a better match on an ECS node
*/
if (ecs != NULL) {
node = NULL;
addr = ecs;
if (env != NULL && env->match_mapped &&
addr->family == AF_INET6 &&
IN6_IS_ADDR_V4MAPPED(&addr->type.in6))
{
isc_netaddr_fromv4mapped(&v4addr, addr);
addr = &v4addr;
}
NETADDR_TO_PREFIX_T(addr, pfx, ecslen, ISC_TRUE);
result = isc_radix_search(acl->iptable->radix, &node, &pfx);
if (result == ISC_R_SUCCESS && node != NULL) {
int off = ISC_RADIX_OFF(&pfx);
if (match_num == -1 ||
node->node_num[off] < match_num)
{
match_num = node->node_num[off];
if (scope != NULL)
*scope = node->bit;
if (*(isc_boolean_t *) node->data[off])
*match = match_num;
else
*match = -match_num;
}
}
isc_refcount_destroy(&pfx.refcount);
}
/* Now search non-radix elements for a match with a lower node_num. */
for (i = 0; i < acl->length; i++) {
dns_aclelement_t *e = &acl->elements[i];
/* Already found a better match? */
if (match_num != -1 && match_num < e->node_num) {
isc_refcount_destroy(&pfx.refcount);
return (ISC_R_SUCCESS);
break;
}
if (dns_aclelement_match(reqaddr, reqsigner,
e, env, matchelt)) {
if (dns_aclelement_match2(reqaddr, reqsigner, ecs, ecslen,
scope, e, env, matchelt))
{
if (match_num == -1 || e->node_num < match_num) {
if (e->negative == ISC_TRUE)
if (e->negative)
*match = -e->node_num;
else
*match = e->node_num;
}
isc_refcount_destroy(&pfx.refcount);
return (ISC_R_SUCCESS);
break;
}
}
isc_refcount_destroy(&pfx.refcount);
return (ISC_R_SUCCESS);
}
@ -349,7 +399,7 @@ dns_acl_merge(dns_acl_t *dest, dns_acl_t *source, isc_boolean_t pos)
#endif
/* reverse sense of positives if this is a negative acl */
if (!pos && source->elements[i].negative == ISC_FALSE) {
if (!pos && !source->elements[i].negative) {
dest->elements[nelem + i].negative = ISC_TRUE;
} else {
dest->elements[nelem + i].negative =
@ -386,10 +436,29 @@ dns_aclelement_match(const isc_netaddr_t *reqaddr,
const dns_aclelement_t *e,
const dns_aclenv_t *env,
const dns_aclelement_t **matchelt)
{
return (dns_aclelement_match2(reqaddr, reqsigner, NULL, 0, NULL,
e, env, matchelt));
}
isc_boolean_t
dns_aclelement_match2(const isc_netaddr_t *reqaddr,
const dns_name_t *reqsigner,
const isc_netaddr_t *ecs,
isc_uint8_t ecslen,
isc_uint8_t *scope,
const dns_aclelement_t *e,
const dns_aclenv_t *env,
const dns_aclelement_t **matchelt)
{
dns_acl_t *inner = NULL;
int indirectmatch;
isc_result_t result;
#ifdef HAVE_GEOIP
const isc_netaddr_t *addr = NULL;
#endif
REQUIRE(ecs != NULL || scope == NULL);
switch (e->type) {
case dns_aclelementtype_keyname:
@ -421,15 +490,17 @@ dns_aclelement_match(const isc_netaddr_t *reqaddr,
case dns_aclelementtype_geoip:
if (env == NULL || env->geoip == NULL)
return (ISC_FALSE);
return (dns_geoip_match(reqaddr, env->geoip, &e->geoip_elem));
addr = (env->geoip_use_ecs && ecs != NULL) ? ecs : reqaddr;
return (dns_geoip_match(addr, scope, env->geoip,
&e->geoip_elem));
#endif
default:
/* Should be impossible. */
INSIST(0);
}
result = dns_acl_match(reqaddr, reqsigner, inner, env,
&indirectmatch, matchelt);
result = dns_acl_match2(reqaddr, reqsigner, ecs, ecslen, scope,
inner, env, &indirectmatch, matchelt);
INSIST(result == ISC_R_SUCCESS);
/*
@ -438,7 +509,6 @@ dns_aclelement_match(const isc_netaddr_t *reqaddr,
* surprise positive match through double negation.
* XXXDCL this should be documented.
*/
if (indirectmatch > 0) {
if (matchelt != NULL)
*matchelt = e;
@ -449,7 +519,6 @@ dns_aclelement_match(const isc_netaddr_t *reqaddr,
* A negative indirect match may have set *matchelt, but we don't
* want it set when we return.
*/
if (matchelt != NULL)
*matchelt = NULL;
@ -519,17 +588,15 @@ initialize_action(void) {
*/
static void
is_insecure(isc_prefix_t *prefix, void **data) {
isc_boolean_t secure;
int bitlen, family;
int bitlen, family, off;
bitlen = prefix->bitlen;
family = prefix->family;
/* Negated entries are always secure. */
secure = * (isc_boolean_t *)data[ISC_IS6(family)];
if (!secure) {
off = ISC_RADIX_OFF(prefix);
if (data[off] != NULL && * (isc_boolean_t *) data[off])
return;
}
/* If loopback prefix found, return */
switch (family) {
@ -628,6 +695,7 @@ dns_aclenv_init(isc_mem_t *mctx, dns_aclenv_t *env) {
env->match_mapped = ISC_FALSE;
#ifdef HAVE_GEOIP
env->geoip = NULL;
env->geoip_use_ecs = ISC_FALSE;
#endif
return (ISC_R_SUCCESS);
@ -644,6 +712,9 @@ dns_aclenv_copy(dns_aclenv_t *t, dns_aclenv_t *s) {
dns_acl_detach(&t->localnets);
dns_acl_attach(s->localnets, &t->localnets);
t->match_mapped = s->match_mapped;
#ifdef HAVE_GEOIP
t->geoip_use_ecs = s->geoip_use_ecs;
#endif
}
void

View File

@ -72,6 +72,7 @@ typedef struct geoip_state {
unsigned int family;
isc_uint32_t ipnum;
geoipv6_t ipnum6;
isc_uint8_t scope;
GeoIPRecord *record;
GeoIPRegion *region;
const char *text;
@ -157,7 +158,7 @@ clean_state(geoip_state_t *state) {
static isc_result_t
set_state(unsigned int family, isc_uint32_t ipnum, const geoipv6_t *ipnum6,
dns_geoip_subtype_t subtype, GeoIPRecord *record,
isc_uint8_t scope, dns_geoip_subtype_t subtype, GeoIPRecord *record,
GeoIPRegion *region, char *name, const char *text, int id)
{
isc_result_t result;
@ -198,6 +199,7 @@ set_state(unsigned int family, isc_uint32_t ipnum, const geoipv6_t *ipnum6,
state->family = family;
state->subtype = subtype;
state->scope = scope;
state->record = record;
state->region = region;
state->name = name;
@ -232,10 +234,12 @@ get_state(void) {
static const char *
country_lookup(GeoIP *db, dns_geoip_subtype_t subtype,
unsigned int family,
isc_uint32_t ipnum, const geoipv6_t *ipnum6)
isc_uint32_t ipnum, const geoipv6_t *ipnum6,
isc_uint8_t *scope)
{
geoip_state_t *prev_state = NULL;
const char *text = NULL;
GeoIPLookup gl;
REQUIRE(db != NULL);
@ -253,42 +257,55 @@ country_lookup(GeoIP *db, dns_geoip_subtype_t subtype,
((prev_state->family == AF_INET && prev_state->ipnum == ipnum) ||
(prev_state->family == AF_INET6 && ipnum6 != NULL &&
memcmp(prev_state->ipnum6.s6_addr, ipnum6->s6_addr, 16) == 0)))
{
text = prev_state->text;
if (scope != NULL)
*scope = prev_state->scope;
}
if (text == NULL) {
switch (subtype) {
case dns_geoip_country_code:
if (family == AF_INET)
text = GeoIP_country_code_by_ipnum(db, ipnum);
text = GeoIP_country_code_by_ipnum_gl(db,
ipnum, &gl);
#ifdef HAVE_GEOIP_V6
else
text = GeoIP_country_code_by_ipnum_v6(db,
*ipnum6);
text = GeoIP_country_code_by_ipnum_v6_gl(db,
*ipnum6, &gl);
#endif
break;
case dns_geoip_country_code3:
if (family == AF_INET)
text = GeoIP_country_code3_by_ipnum(db, ipnum);
text = GeoIP_country_code3_by_ipnum_gl(db,
ipnum, &gl);
#ifdef HAVE_GEOIP_V6
else
text = GeoIP_country_code3_by_ipnum_v6(db,
*ipnum6);
text = GeoIP_country_code3_by_ipnum_v6_gl(db,
*ipnum6, &gl);
#endif
break;
case dns_geoip_country_name:
if (family == AF_INET)
text = GeoIP_country_name_by_ipnum(db, ipnum);
text = GeoIP_country_name_by_ipnum_gl(db,
ipnum, &gl);
#ifdef HAVE_GEOIP_V6
else
text = GeoIP_country_name_by_ipnum_v6(db,
*ipnum6);
text = GeoIP_country_name_by_ipnum_v6_gl(db,
*ipnum6, &gl);
#endif
break;
default:
INSIST(0);
}
set_state(family, ipnum, ipnum6, subtype,
if (text == NULL)
return (NULL);
if (scope != NULL)
*scope = gl.netmask;
set_state(family, ipnum, ipnum6, gl.netmask, subtype,
NULL, NULL, NULL, text, 0);
}
@ -377,7 +394,9 @@ is_city(dns_geoip_subtype_t subtype) {
*/
static GeoIPRecord *
city_lookup(GeoIP *db, dns_geoip_subtype_t subtype,
unsigned int family, isc_uint32_t ipnum, const geoipv6_t *ipnum6)
unsigned int family, isc_uint32_t ipnum,
const geoipv6_t *ipnum6,
isc_uint8_t *scope)
{
GeoIPRecord *record = NULL;
geoip_state_t *prev_state = NULL;
@ -397,7 +416,11 @@ city_lookup(GeoIP *db, dns_geoip_subtype_t subtype,
((prev_state->family == AF_INET && prev_state->ipnum == ipnum) ||
(prev_state->family == AF_INET6 &&
memcmp(prev_state->ipnum6.s6_addr, ipnum6->s6_addr, 16) == 0)))
{
record = prev_state->record;
if (scope != NULL)
*scope = record->netmask;
}
if (record == NULL) {
if (family == AF_INET)
@ -409,15 +432,17 @@ city_lookup(GeoIP *db, dns_geoip_subtype_t subtype,
if (record == NULL)
return (NULL);
set_state(family, ipnum, ipnum6, subtype,
if (scope != NULL)
*scope = record->netmask;
set_state(family, ipnum, ipnum6, record->netmask, subtype,
record, NULL, NULL, NULL, 0);
}
return (record);
}
static char *
region_string(GeoIPRegion *region, dns_geoip_subtype_t subtype, int *maxlen) {
static char * region_string(GeoIPRegion *region, dns_geoip_subtype_t subtype, int *maxlen) {
const char *s;
char *deconst;
@ -459,9 +484,12 @@ is_region(dns_geoip_subtype_t subtype) {
* outside the Region database.
*/
static GeoIPRegion *
region_lookup(GeoIP *db, dns_geoip_subtype_t subtype, isc_uint32_t ipnum) {
region_lookup(GeoIP *db, dns_geoip_subtype_t subtype,
isc_uint32_t ipnum, isc_uint8_t *scope)
{
GeoIPRegion *region = NULL;
geoip_state_t *prev_state = NULL;
GeoIPLookup gl;
REQUIRE(db != NULL);
@ -469,14 +497,21 @@ region_lookup(GeoIP *db, dns_geoip_subtype_t subtype, isc_uint32_t ipnum) {
if (prev_state != NULL && prev_state->ipnum == ipnum &&
is_region(prev_state->subtype))
{
region = prev_state->region;
if (scope != NULL)
*scope = prev_state->scope;
}
if (region == NULL) {
region = GeoIP_region_by_ipnum(db, ipnum);
region = GeoIP_region_by_ipnum_gl(db, ipnum, &gl);
if (region == NULL)
return (NULL);
set_state(AF_INET, ipnum, NULL,
if (scope != NULL)
*scope = gl.netmask;
set_state(AF_INET, ipnum, NULL, gl.netmask,
subtype, NULL, region, NULL, NULL, 0);
}
@ -489,9 +524,12 @@ region_lookup(GeoIP *db, dns_geoip_subtype_t subtype, isc_uint32_t ipnum) {
* or was for a search of a different subtype.
*/
static char *
name_lookup(GeoIP *db, dns_geoip_subtype_t subtype, isc_uint32_t ipnum) {
name_lookup(GeoIP *db, dns_geoip_subtype_t subtype,
isc_uint32_t ipnum, isc_uint8_t *scope)
{
char *name = NULL;
geoip_state_t *prev_state = NULL;
GeoIPLookup gl;
REQUIRE(db != NULL);
@ -499,14 +537,21 @@ name_lookup(GeoIP *db, dns_geoip_subtype_t subtype, isc_uint32_t ipnum) {
if (prev_state != NULL && prev_state->ipnum == ipnum &&
prev_state->subtype == subtype)
{
name = prev_state->name;
if (scope != NULL)
*scope = prev_state->scope;
}
if (name == NULL) {
name = GeoIP_name_by_ipnum(db, ipnum);
name = GeoIP_name_by_ipnum_gl(db, ipnum, &gl);
if (name == NULL)
return (NULL);
set_state(AF_INET, ipnum, NULL,
if (scope != NULL)
*scope = gl.netmask;
set_state(AF_INET, ipnum, NULL, gl.netmask,
subtype, NULL, NULL, name, NULL, 0);
}
@ -519,9 +564,12 @@ name_lookup(GeoIP *db, dns_geoip_subtype_t subtype, isc_uint32_t ipnum) {
* different subtype.
*/
static int
netspeed_lookup(GeoIP *db, dns_geoip_subtype_t subtype, isc_uint32_t ipnum) {
netspeed_lookup(GeoIP *db, dns_geoip_subtype_t subtype,
isc_uint32_t ipnum, isc_uint8_t *scope)
{
geoip_state_t *prev_state = NULL;
isc_boolean_t found = ISC_FALSE;
GeoIPLookup gl;
int id = -1;
REQUIRE(db != NULL);
@ -531,12 +579,20 @@ netspeed_lookup(GeoIP *db, dns_geoip_subtype_t subtype, isc_uint32_t ipnum) {
if (prev_state != NULL && prev_state->ipnum == ipnum &&
prev_state->subtype == subtype) {
id = prev_state->id;
if (scope != NULL)
*scope = prev_state->scope;
found = ISC_TRUE;
}
if (!found) {
id = GeoIP_id_by_ipnum(db, ipnum);
set_state(AF_INET, ipnum, NULL,
id = GeoIP_id_by_ipnum_gl(db, ipnum, &gl);
if (id == 0)
return (0);
if (scope != NULL)
*scope = gl.netmask;
set_state(AF_INET, ipnum, NULL, gl.netmask,
subtype, NULL, NULL, NULL, NULL, id);
}
@ -599,7 +655,7 @@ fix_subtype(const isc_netaddr_t *reqaddr, const dns_geoip_databases_t *geoip,
#endif /* HAVE_GEOIP */
isc_boolean_t
dns_geoip_match(const isc_netaddr_t *reqaddr,
dns_geoip_match(const isc_netaddr_t *reqaddr, isc_uint8_t *scope,
const dns_geoip_databases_t *geoip,
const dns_geoip_elem_t *elt)
{
@ -662,7 +718,7 @@ dns_geoip_match(const isc_netaddr_t *reqaddr,
INSIST(elt->as_string != NULL);
cs = country_lookup(db, subtype, family, ipnum, ipnum6);
cs = country_lookup(db, subtype, family, ipnum, ipnum6, scope);
if (cs != NULL && strncasecmp(elt->as_string, cs, maxlen) == 0)
return (ISC_TRUE);
break;
@ -682,7 +738,8 @@ dns_geoip_match(const isc_netaddr_t *reqaddr,
if (db == NULL)
return (ISC_FALSE);
record = city_lookup(db, subtype, family, ipnum, ipnum6);
record = city_lookup(db, subtype, family,
ipnum, ipnum6, scope);
if (record == NULL)
break;
@ -697,7 +754,8 @@ dns_geoip_match(const isc_netaddr_t *reqaddr,
if (db == NULL)
return (ISC_FALSE);
record = city_lookup(db, subtype, family, ipnum, ipnum6);
record = city_lookup(db, subtype, family,
ipnum, ipnum6, scope);
if (record == NULL)
break;
@ -710,7 +768,8 @@ dns_geoip_match(const isc_netaddr_t *reqaddr,
if (db == NULL)
return (ISC_FALSE);
record = city_lookup(db, subtype, family, ipnum, ipnum6);
record = city_lookup(db, subtype, family,
ipnum, ipnum6, scope);
if (record == NULL)
break;
@ -731,7 +790,7 @@ dns_geoip_match(const isc_netaddr_t *reqaddr,
if (family == AF_INET6)
return (ISC_FALSE);
region = region_lookup(geoip->region, subtype, ipnum);
region = region_lookup(geoip->region, subtype, ipnum, scope);
if (region == NULL)
break;
@ -765,9 +824,22 @@ dns_geoip_match(const isc_netaddr_t *reqaddr,
if (family == AF_INET6)
return (ISC_FALSE);
s = name_lookup(db, subtype, ipnum);
if (s != NULL && strcasecmp(elt->as_string, s) == 0)
return (ISC_TRUE);
s = name_lookup(db, subtype, ipnum, scope);
if (s != NULL) {
size_t l;
if (strcasecmp(elt->as_string, s) == 0)
return (ISC_TRUE);
if (subtype != dns_geoip_as_asnum)
break;
/*
* Just check if the ASNNNN value matches.
*/
l = strlen(elt->as_string);
if (l > 0U && strchr(elt->as_string, ' ') == NULL &&
strncasecmp(elt->as_string, s, l) == 0 &&
s[l] == ' ')
return (ISC_TRUE);
}
break;
case dns_geoip_netspeed_id:
@ -777,7 +849,7 @@ dns_geoip_match(const isc_netaddr_t *reqaddr,
if (family == AF_INET6)
return (ISC_FALSE);
id = netspeed_lookup(geoip->netspeed, subtype, ipnum);
id = netspeed_lookup(geoip->netspeed, subtype, ipnum, scope);
if (id == elt->as_int)
return (ISC_TRUE);
break;

View File

@ -103,6 +103,7 @@ struct dns_aclenv {
isc_boolean_t match_mapped;
#ifdef HAVE_GEOIP
dns_geoip_databases_t *geoip;
isc_boolean_t geoip_use_ecs;
#endif
};
@ -212,12 +213,28 @@ dns_acl_match(const isc_netaddr_t *reqaddr,
const dns_aclenv_t *env,
int *match,
const dns_aclelement_t **matchelt);
isc_result_t
dns_acl_match2(const isc_netaddr_t *reqaddr,
const dns_name_t *reqsigner,
const isc_netaddr_t *ecs,
isc_uint8_t ecslen,
isc_uint8_t *scope,
const dns_acl_t *acl,
const dns_aclenv_t *env,
int *match,
const dns_aclelement_t **matchelt);
/*%<
* General, low-level ACL matching. This is expected to
* be useful even for weird stuff like the topology and sortlist statements.
*
* Match the address 'reqaddr', and optionally the key name 'reqsigner',
* against 'acl'. 'reqsigner' may be NULL.
* and optionally the client prefix 'ecs' of length 'ecslen'
* (reported via EDNS client subnet option) against 'acl'.
*
* 'reqsigner' and 'ecs' may be NULL. If an ACL matches against 'ecs'
* and 'ecslen', then 'scope' will be set to indicate the netmask that
* matched.
*
* If there is a match, '*match' will be set to an integer whose absolute
* value corresponds to the order in which the matching value was inserted
@ -244,6 +261,16 @@ dns_aclelement_match(const isc_netaddr_t *reqaddr,
const dns_aclelement_t *e,
const dns_aclenv_t *env,
const dns_aclelement_t **matchelt);
isc_boolean_t
dns_aclelement_match2(const isc_netaddr_t *reqaddr,
const dns_name_t *reqsigner,
const isc_netaddr_t *ecs,
isc_uint8_t ecslen,
isc_uint8_t *scope,
const dns_aclelement_t *e,
const dns_aclenv_t *env,
const dns_aclelement_t **matchelt);
/*%<
* Like dns_acl_match, but matches against the single ACL element 'e'
* rather than a complete ACL, and returns ISC_TRUE iff it matched.

View File

@ -108,7 +108,7 @@ typedef struct dns_geoip_databases {
ISC_LANG_BEGINDECLS
isc_boolean_t
dns_geoip_match(const isc_netaddr_t *reqaddr,
dns_geoip_match(const isc_netaddr_t *reqaddr, isc_uint8_t *scope,
const dns_geoip_databases_t *geoip,
const dns_geoip_elem_t *elt);

View File

@ -51,6 +51,10 @@ dns_iptable_create(isc_mem_t *mctx, dns_iptable_t **target);
isc_result_t
dns_iptable_addprefix(dns_iptable_t *tab, isc_netaddr_t *addr,
isc_uint16_t bitlen, isc_boolean_t pos);
isc_result_t
dns_iptable_addprefix2(dns_iptable_t *tab, isc_netaddr_t *addr,
isc_uint16_t bitlen, isc_boolean_t pos,
isc_boolean_t is_ecs);
/*
* Add an IP prefix to an existing IP table
*/

View File

@ -112,7 +112,7 @@
#define DNS_OPT_SIT 65001 /*%< SIT opt code */
/*%< The number of EDNS options we know about. */
#define DNS_EDNSOPTIONS 4
#define DNS_EDNSOPTIONS 5
#define DNS_MESSAGE_REPLYPRESERVE (DNS_MESSAGEFLAG_RD|DNS_MESSAGEFLAG_CD)
#define DNS_MESSAGEEXTFLAG_REPLYPRESERVE (DNS_MESSAGEEXTFLAG_DO)

View File

@ -14,8 +14,6 @@
* PERFORMANCE OF THIS SOFTWARE.
*/
/* $Id: iptable.c,v 1.15 2009/02/18 23:47:48 tbox Exp $ */
#include <config.h>
#include <isc/mem.h>
@ -63,16 +61,24 @@ isc_boolean_t dns_iptable_pos = ISC_TRUE;
isc_result_t
dns_iptable_addprefix(dns_iptable_t *tab, isc_netaddr_t *addr,
isc_uint16_t bitlen, isc_boolean_t pos)
{
return(dns_iptable_addprefix2(tab, addr, bitlen, pos, ISC_FALSE));
}
isc_result_t
dns_iptable_addprefix2(dns_iptable_t *tab, isc_netaddr_t *addr,
isc_uint16_t bitlen, isc_boolean_t pos,
isc_boolean_t is_ecs)
{
isc_result_t result;
isc_prefix_t pfx;
isc_radix_node_t *node = NULL;
int family;
int i;
INSIST(DNS_IPTABLE_VALID(tab));
INSIST(tab->radix);
NETADDR_TO_PREFIX_T(addr, pfx, bitlen);
NETADDR_TO_PREFIX_T(addr, pfx, bitlen, is_ecs);
result = isc_radix_insert(tab->radix, &node, NULL, &pfx);
if (result != ISC_R_SUCCESS) {
@ -81,28 +87,20 @@ dns_iptable_addprefix(dns_iptable_t *tab, isc_netaddr_t *addr,
}
/* If a node already contains data, don't overwrite it */
family = pfx.family;
if (family == AF_UNSPEC) {
if (pfx.family == AF_UNSPEC) {
/* "any" or "none" */
INSIST(pfx.bitlen == 0);
if (pos) {
if (node->data[0] == NULL)
node->data[0] = &dns_iptable_pos;
if (node->data[1] == NULL)
node->data[1] = &dns_iptable_pos;
} else {
if (node->data[0] == NULL)
node->data[0] = &dns_iptable_neg;
if (node->data[1] == NULL)
node->data[1] = &dns_iptable_neg;
for (i = 0; i < 4; i++) {
if (node->data[i] == NULL)
node->data[i] = pos ? &dns_iptable_pos
: &dns_iptable_neg;
}
} else {
/* any other prefix */
if (node->data[ISC_IS6(family)] == NULL) {
if (pos)
node->data[ISC_IS6(family)] = &dns_iptable_pos;
else
node->data[ISC_IS6(family)] = &dns_iptable_neg;
int offset = ISC_RADIX_OFF(&pfx);
if (node->data[offset] == NULL) {
node->data[offset] = pos ? &dns_iptable_pos
: &dns_iptable_neg;
}
}
@ -118,7 +116,7 @@ dns_iptable_merge(dns_iptable_t *tab, dns_iptable_t *source, isc_boolean_t pos)
{
isc_result_t result;
isc_radix_node_t *node, *new_node;
int max_node = 0;
int i, max_node = 0;
RADIX_WALK (source->radix->head, node) {
new_node = NULL;
@ -135,20 +133,15 @@ dns_iptable_merge(dns_iptable_t *tab, dns_iptable_t *source, isc_boolean_t pos)
* could be a security risk. To prevent this, we
* just leave the negative nodes negative.
*/
if (!pos) {
if (node->data[0] &&
*(isc_boolean_t *) node->data[0] == ISC_TRUE)
new_node->data[0] = &dns_iptable_neg;
if (node->data[1] &&
*(isc_boolean_t *) node->data[1] == ISC_TRUE)
new_node->data[1] = &dns_iptable_neg;
for (i = 0; i < 4; i++) {
if (!pos) {
if (node->data[i] &&
*(isc_boolean_t *) node->data[i])
new_node->data[i] = &dns_iptable_neg;
}
if (node->node_num[i] > max_node)
max_node = node->node_num[i];
}
if (node->node_num[0] > max_node)
max_node = node->node_num[0];
if (node->node_num[1] > max_node)
max_node = node->node_num[1];
} RADIX_WALK_END;
tab->radix->num_added_node += max_node;

View File

@ -15,8 +15,6 @@
* PERFORMANCE OF THIS SOFTWARE.
*/
/* $Id$ */
/*! \file */
/***

View File

@ -80,11 +80,13 @@
DNS_LOGMODULE_RESOLVER, \
ISC_LOG_DEBUG(3), \
"res %p: %s", (r), (m))
#define FCTXTRACE(m) isc_log_write(dns_lctx, \
#define FCTXTRACE(m) \
isc_log_write(dns_lctx, \
DNS_LOGCATEGORY_RESOLVER, \
DNS_LOGMODULE_RESOLVER, \
ISC_LOG_DEBUG(3), \
"fctx %p(%s): %s", fctx, fctx->info, (m))
"fctx %p(%s): %s", \
fctx, fctx->info, (m))
#define FCTXTRACE2(m1, m2) \
isc_log_write(dns_lctx, \
DNS_LOGCATEGORY_RESOLVER, \
@ -92,6 +94,22 @@
ISC_LOG_DEBUG(3), \
"fctx %p(%s): %s %s", \
fctx, fctx->info, (m1), (m2))
#define FCTXTRACE3(m, res) \
isc_log_write(dns_lctx, \
DNS_LOGCATEGORY_RESOLVER, \
DNS_LOGMODULE_RESOLVER, \
ISC_LOG_DEBUG(3), \
"fctx %p(%s): [result: %s] %s", \
fctx, fctx->info, \
isc_result_totext(res), (m))
#define FCTXTRACE4(m1, m2, res) \
isc_log_write(dns_lctx, \
DNS_LOGCATEGORY_RESOLVER, \
DNS_LOGMODULE_RESOLVER, \
ISC_LOG_DEBUG(3), \
"fctx %p(%s): [result: %s] %s %s", \
fctx, fctx->info, \
isc_result_totext(res), (m1), (m2))
#define FTRACE(m) isc_log_write(dns_lctx, \
DNS_LOGCATEGORY_RESOLVER, \
DNS_LOGMODULE_RESOLVER, \
@ -1268,6 +1286,9 @@ process_sendevent(resquery_t *query, isc_event_t *event) {
case ISC_R_NOPERM:
case ISC_R_ADDRNOTAVAIL:
case ISC_R_CONNREFUSED:
FCTXTRACE3("query canceled in sendevent(): "
"no route to host; no response",
sevent->result);
/*
* No route to remote.
@ -1279,6 +1300,10 @@ process_sendevent(resquery_t *query, isc_event_t *event) {
break;
default:
FCTXTRACE3("query canceled in sendevent() due to "
"unexpected event result; responding",
sevent->result);
fctx_cancelquery(&query, NULL, NULL, ISC_FALSE);
break;
}
@ -2359,6 +2384,9 @@ resquery_connected(isc_task_t *task, isc_event_t *event) {
isc_interval_set(&interval, 20, 0);
result = fctx_startidletimer(query->fctx, &interval);
if (result != ISC_R_SUCCESS) {
FCTXTRACE("query canceled: idle timer failed; "
"responding");
fctx_cancelquery(&query, NULL, NULL, ISC_FALSE);
fctx_done(fctx, result, __LINE__);
break;
@ -2395,6 +2423,9 @@ resquery_connected(isc_task_t *task, isc_event_t *event) {
result = resquery_send(query);
if (result != ISC_R_SUCCESS) {
FCTXTRACE("query canceled: "
"resquery_send() failed; responding");
fctx_cancelquery(&query, NULL, NULL, ISC_FALSE);
fctx_done(fctx, result, __LINE__);
}
@ -2406,6 +2437,10 @@ resquery_connected(isc_task_t *task, isc_event_t *event) {
case ISC_R_NOPERM:
case ISC_R_ADDRNOTAVAIL:
case ISC_R_CONNECTIONRESET:
FCTXTRACE3("query canceled in connected(): "
"no route to host; no response",
sevent->result);
/*
* No route to remote.
*/
@ -2415,6 +2450,10 @@ resquery_connected(isc_task_t *task, isc_event_t *event) {
break;
default:
FCTXTRACE3("query canceled in connected() due to "
"unexpected event result; responding",
sevent->result);
isc_socket_detach(&query->tcpsocket);
fctx_cancelquery(&query, NULL, NULL, ISC_FALSE);
break;
@ -2495,11 +2534,12 @@ fctx_finddone(isc_task_t *task, isc_event_t *event) {
isc_event_free(&event);
dns_adb_destroyfind(&find);
if (want_try)
if (want_try) {
fctx_try(fctx, ISC_TRUE, ISC_FALSE);
else if (want_done)
} else if (want_done) {
FCTXTRACE("fetch failed in finddone(); return ISC_R_FAILURE");
fctx_done(fctx, ISC_R_FAILURE, __LINE__);
else if (destroy) {
} else if (destroy) {
fctx_destroy(fctx);
if (bucket_empty)
empty_bucket(res);
@ -3479,6 +3519,7 @@ fctx_timeout(isc_task_t *task, isc_event_t *event) {
fctx->timeouts++;
fctx->timeout = ISC_TRUE;
/*
* We could cancel the running queries here, or we could let
* them keep going. Since we normally use separate sockets for
@ -3490,10 +3531,13 @@ fctx_timeout(isc_task_t *task, isc_event_t *event) {
*/
query = ISC_LIST_HEAD(fctx->queries);
if (query != NULL &&
isc_time_compare(&tevent->due, &query->start) >= 0) {
isc_time_compare(&tevent->due, &query->start) >= 0)
{
FCTXTRACE("query timed out; no response");
fctx_cancelquery(&query, NULL, NULL, ISC_TRUE);
}
fctx->attributes &= ~FCTX_ATTR_ADDRWAIT;
/*
* Our timer has triggered. Reestablish the fctx lifetime
* timer.
@ -3777,7 +3821,6 @@ fctx_create(dns_resolver_t *res, dns_name_t *name, dns_rdatatype_t type,
unsigned int findoptions = 0;
char buf[DNS_NAME_FORMATSIZE + DNS_RDATATYPE_FORMATSIZE];
char typebuf[DNS_RDATATYPE_FORMATSIZE];
dns_name_t suffix;
isc_mem_t *mctx;
/*
@ -3789,6 +3832,11 @@ fctx_create(dns_resolver_t *res, dns_name_t *name, dns_rdatatype_t type,
fctx = isc_mem_get(mctx, sizeof(*fctx));
if (fctx == NULL)
return (ISC_R_NOMEMORY);
/*
* Make fctx->info point to a copy of a formatted string
* "name/type".
*/
dns_name_format(name, buf, sizeof(buf));
dns_rdatatype_format(type, typebuf, sizeof(typebuf));
strcat(buf, "/"); /* checked */
@ -3798,6 +3846,7 @@ fctx_create(dns_resolver_t *res, dns_name_t *name, dns_rdatatype_t type,
result = ISC_R_NOMEMORY;
goto cleanup_fetch;
}
FCTXTRACE("create");
dns_name_init(&fctx->name, NULL);
result = dns_name_dup(name, mctx, &fctx->name);
@ -3870,10 +3919,12 @@ fctx_create(dns_resolver_t *res, dns_name_t *name, dns_rdatatype_t type,
dns_forwarders_t *forwarders = NULL;
unsigned int labels;
dns_name_t *fwdname = name;
dns_name_t suffix;
/*
* DS records are found in the parent server.
* Strip label to get the correct forwarder (if any).
* DS records are found in the parent server. Strip one
* leading label from the name (to be used in finding
* the forwarder).
*/
if (dns_rdatatype_atparent(fctx->type) &&
dns_name_countlabels(name) > 1) {
@ -3882,6 +3933,8 @@ fctx_create(dns_resolver_t *res, dns_name_t *name, dns_rdatatype_t type,
dns_name_getlabelsequence(name, 1, labels - 1, &suffix);
fwdname = &suffix;
}
/* Find the forwarder for this name. */
dns_fixedname_init(&fixed);
domain = dns_fixedname_name(&fixed);
result = dns_fwdtable_find2(fctx->res->view->fwdtable, fwdname,
@ -7170,6 +7223,7 @@ resquery_response(isc_task_t *task, isc_event_t *event) {
if (fctx->res->exiting) {
result = ISC_R_SHUTTINGDOWN;
FCTXTRACE("resolver shutting down");
goto done;
}
@ -7224,6 +7278,7 @@ resquery_response(isc_task_t *task, isc_event_t *event) {
no_response = ISC_TRUE;
}
}
FCTXTRACE3("dispatcher failure", devent->result);
goto done;
}
@ -7231,14 +7286,18 @@ resquery_response(isc_task_t *task, isc_event_t *event) {
if (query->tsig != NULL) {
result = dns_message_setquerytsig(message, query->tsig);
if (result != ISC_R_SUCCESS)
if (result != ISC_R_SUCCESS) {
FCTXTRACE3("unable to set query tsig", result);
goto done;
}
}
if (query->tsigkey) {
result = dns_message_settsigkey(message, query->tsigkey);
if (result != ISC_R_SUCCESS)
if (result != ISC_R_SUCCESS) {
FCTXTRACE3("unable to set tsig key", result);
goto done;
}
}
if ((options & DNS_FETCHOPT_TCP) == 0) {
@ -7250,6 +7309,7 @@ resquery_response(isc_task_t *task, isc_event_t *event) {
}
result = dns_message_parse(message, &devent->buffer, 0);
if (result != ISC_R_SUCCESS) {
FCTXTRACE3("message failed to parse", result);
switch (result) {
case ISC_R_UNEXPECTEDEND:
if (!message->question_ok ||
@ -7338,6 +7398,7 @@ resquery_response(isc_task_t *task, isc_event_t *event) {
*/
resend = ISC_TRUE;
/* XXXMPA log it */
FCTXTRACE("bad sit");
goto done;
}
#endif
@ -7348,8 +7409,10 @@ resquery_response(isc_task_t *task, isc_event_t *event) {
* returns success anyway.
*/
result = dns_message_checksig(message, fctx->res->view);
if (result != ISC_R_SUCCESS)
if (result != ISC_R_SUCCESS) {
FCTXTRACE3("signature check failed", result);
goto done;
}
/*
* The dispatcher should ensure we only get responses with QR set.
@ -7453,6 +7516,7 @@ resquery_response(isc_task_t *task, isc_event_t *event) {
options |= DNS_FETCHOPT_TCP;
resend = ISC_TRUE;
}
FCTXTRACE3("message truncated", result);
goto done;
}
@ -7463,6 +7527,7 @@ resquery_response(isc_task_t *task, isc_event_t *event) {
/* XXXRTH Log */
broken_server = DNS_R_UNEXPECTEDOPCODE;
keep_trying = ISC_TRUE;
FCTXTRACE("invalid message opcode");
goto done;
}
@ -7497,6 +7562,8 @@ resquery_response(isc_task_t *task, isc_event_t *event) {
*/
if (message->rcode != dns_rcode_noerror &&
message->rcode != dns_rcode_nxdomain) {
isc_buffer_t b;
char code[64];
#ifdef ISC_PLATFORM_USESIT
unsigned char sit[64];
@ -7623,6 +7690,11 @@ resquery_response(isc_task_t *task, isc_event_t *event) {
INSIST(broken_server != ISC_R_SUCCESS);
keep_trying = ISC_TRUE;
}
isc_buffer_init(&b, code, sizeof(code) - 1);
dns_rcode_totext(fctx->rmessage->rcode, &b);
code[isc_buffer_usedlength(&b)] = '\0';
FCTXTRACE2("remote server broken: returned ", code);
goto done;
}
@ -7634,6 +7706,7 @@ resquery_response(isc_task_t *task, isc_event_t *event) {
/* XXXRTH Log */
if (result == DNS_R_FORMERR)
keep_trying = ISC_TRUE;
FCTXTRACE3("response did not match question", result);
goto done;
}
@ -7654,6 +7727,7 @@ resquery_response(isc_task_t *task, isc_event_t *event) {
isc_result_totext(result));
broken_server = DNS_R_LAME;
keep_trying = ISC_TRUE;
FCTXTRACE("lame server");
goto done;
}
@ -7706,22 +7780,32 @@ resquery_response(isc_task_t *task, isc_event_t *event) {
*/
if ((message->flags & DNS_MESSAGEFLAG_AA) != 0 ||
ISFORWARDER(query->addrinfo))
{
result = answer_response(fctx);
else if (iscname(fctx) &&
if (result != ISC_R_SUCCESS)
FCTXTRACE3("answer_response (AA/fwd)", result);
} else if (iscname(fctx) &&
fctx->type != dns_rdatatype_any &&
fctx->type != dns_rdatatype_cname) {
fctx->type != dns_rdatatype_cname)
{
/*
* A BIND8 server could return a non-authoritative
* answer when a CNAME is followed. We should treat
* it as a valid answer.
*/
result = answer_response(fctx);
if (result != ISC_R_SUCCESS)
FCTXTRACE3("answer_response (!ANY/!CNAME)",
result);
} else if (fctx->type != dns_rdatatype_ns &&
!betterreferral(fctx)) {
/*
* Lame response !!!.
*/
result = answer_response(fctx);
if (result != ISC_R_SUCCESS)
FCTXTRACE("answer_response (!NS)");
FCTXTRACE3("answer_response (!NS)", result);
} else {
if (fctx->type == dns_rdatatype_ns) {
/*
@ -7734,6 +7818,9 @@ resquery_response(isc_task_t *task, isc_event_t *event) {
*/
result = noanswer_response(fctx, NULL,
LOOK_FOR_NS_IN_ANSWER);
if (result != ISC_R_SUCCESS)
FCTXTRACE3("noanswer_response (NS)",
result);
} else {
/*
* Some other servers may still somehow include
@ -7749,6 +7836,8 @@ resquery_response(isc_task_t *task, isc_event_t *event) {
*/
result = noanswer_response(fctx, NULL,
LOOK_FOR_GLUE_IN_ANSWER);
if (result != ISC_R_SUCCESS)
FCTXTRACE3("noanswer_response", result);
}
if (result != DNS_R_DELEGATION) {
/*
@ -7813,6 +7902,7 @@ resquery_response(isc_task_t *task, isc_event_t *event) {
*/
if (result == DNS_R_FORMERR)
keep_trying = ISC_TRUE;
FCTXTRACE3("noanswer_response", result);
goto done;
}
} else {
@ -7822,6 +7912,7 @@ resquery_response(isc_task_t *task, isc_event_t *event) {
/* XXXRTH Log */
broken_server = DNS_R_UNEXPECTEDRCODE;
keep_trying = ISC_TRUE;
FCTXTRACE("broken server: unexpected rcode");
goto done;
}
@ -7836,8 +7927,10 @@ resquery_response(isc_task_t *task, isc_event_t *event) {
*/
if (WANTCACHE(fctx)) {
result = cache_message(fctx, query->addrinfo, now);
if (result != ISC_R_SUCCESS)
if (result != ISC_R_SUCCESS) {
FCTXTRACE3("cache_message complete", result);
goto done;
}
}
/*
@ -7855,6 +7948,8 @@ resquery_response(isc_task_t *task, isc_event_t *event) {
* Cache any negative cache entries in the message.
*/
result = ncache_message(fctx, query->addrinfo, covers, now);
if (result != ISC_R_SUCCESS)
FCTXTRACE3("ncache_message complete", result);
}
done:
@ -7864,6 +7959,10 @@ resquery_response(isc_task_t *task, isc_event_t *event) {
*/
addrinfo = query->addrinfo;
FCTXTRACE4("query canceled in response(); ",
no_response ? "no response" : "responding",
result);
/*
* Cancel the query.
*
@ -8616,6 +8715,10 @@ log_fetch(dns_name_t *name, dns_rdatatype_t type) {
char typebuf[DNS_RDATATYPE_FORMATSIZE];
int level = ISC_LOG_DEBUG(1);
/*
* If there's no chance of logging it, don't render (format) the
* name and RDATA type (further below), and return early.
*/
if (! isc_log_wouldlog(dns_lctx, level))
return;
@ -9022,6 +9125,11 @@ dns_resolver_flushbadcache(dns_resolver_t *resolver, dns_name_t *name) {
unsigned int i;
dns_badcache_t *bad, *prev, *next;
/*
* Drop all entries that match the name, and also all expired
* entries from the badcache.
*/
REQUIRE(VALID_RESOLVER(resolver));
LOCK(&resolver->lock);
@ -9066,6 +9174,8 @@ dns_resolver_flushbadnames(dns_resolver_t *resolver, dns_name_t *name) {
isc_time_t now;
isc_result_t result;
/* Drop all expired entries from the badcache. */
REQUIRE(VALID_RESOLVER(resolver));
REQUIRE(name != NULL);
@ -9105,6 +9215,13 @@ resizehash(dns_resolver_t *resolver, isc_time_t *now, isc_boolean_t grow) {
dns_badcache_t **new, *bad, *next;
unsigned int i;
/*
* The number of buckets in the hashtable is modified in this
* function. Afterwards, all the entries are remapped into the
* corresponding new slot. Rehashing (hash computation) is
* unnecessary as the hash values had been saved.
*/
if (grow)
newsize = resolver->badhash * 2 + 1;
else
@ -9115,6 +9232,13 @@ resizehash(dns_resolver_t *resolver, isc_time_t *now, isc_boolean_t grow) {
if (new == NULL)
return;
memset(new, 0, sizeof(*resolver->badcache) * newsize);
/*
* Because the hashtable implements a simple modulus mapping
* from hash to bucket (no extendible hashing is used), every
* name in the hashtable has to be remapped to its new slot.
* Entries that have expired (time) are dropped.
*/
for (i = 0; i < resolver->badhash; i++) {
for (bad = resolver->badcache[i]; bad != NULL; bad = next) {
next = bad->next;
@ -9143,6 +9267,18 @@ dns_resolver_addbadcache(dns_resolver_t *resolver, dns_name_t *name,
unsigned int i, hashval;
dns_badcache_t *bad, *prev, *next;
/*
* The badcache is implemented as a hashtable keyed on the name,
* and each bucket slot points to a linked list (separate
* chaining).
*
* To avoid long list chains, if the number of entries in the
* hashtable goes over number-of-buckets * 8, the
* number-of-buckets is doubled. Similarly, if the number of
* entries goes below number-of-buckets * 2, the number-of-buckets
* is halved. See resizehash().
*/
REQUIRE(VALID_RESOLVER(resolver));
LOCK(&resolver->lock);
@ -9167,6 +9303,7 @@ dns_resolver_addbadcache(dns_resolver_t *resolver, dns_name_t *name,
next = bad->next;
if (bad->type == type && dns_name_equal(name, &bad->name))
break;
/* Drop expired entries when walking the chain. */
if (isc_time_compare(&bad->expire, &now) < 0) {
if (prev == NULL)
resolver->badcache[i] = bad->next;
@ -9179,6 +9316,12 @@ dns_resolver_addbadcache(dns_resolver_t *resolver, dns_name_t *name,
prev = bad;
}
if (bad == NULL) {
/*
* Insert the name into the badcache hashtable at the
* head of the linked list at the appropriate slot. The
* name data follows right after the allocation for the
* linked list node.
*/
isc_buffer_t buffer;
bad = isc_mem_get(resolver->mctx, sizeof(*bad) + name->length);
if (bad == NULL)
@ -9337,6 +9480,12 @@ dns_resolver_disable_algorithm(dns_resolver_t *resolver, dns_name_t *name,
isc_result_t result;
dns_rbtnode_t *node = NULL;
/*
* Whether an algorithm is disabled (or not) is stored in a
* per-name bitfield that is stored as the node data of an
* RBT.
*/
REQUIRE(VALID_RESOLVER(resolver));
if (alg > 255)
return (ISC_R_RANGE);
@ -9358,7 +9507,17 @@ dns_resolver_disable_algorithm(dns_resolver_t *resolver, dns_name_t *name,
if (result == ISC_R_SUCCESS || result == ISC_R_EXISTS) {
algorithms = node->data;
/*
* If algorithms is set, algorithms[0] contains its
* length.
*/
if (algorithms == NULL || len > *algorithms) {
/*
* If no bitfield exists in the node data, or if
* it is not long enough, allocate a new
* bitfield and copy the old (smaller) bitfield
* into it if one exists.
*/
new = isc_mem_get(resolver->mctx, len);
if (new == NULL) {
result = ISC_R_NOMEMORY;
@ -9368,8 +9527,10 @@ dns_resolver_disable_algorithm(dns_resolver_t *resolver, dns_name_t *name,
if (algorithms != NULL)
memmove(new, algorithms, *algorithms);
new[len-1] |= mask;
/* new[0] should contain the length of new. */
*new = len;
node->data = new;
/* Free the older bitfield. */
if (algorithms != NULL)
isc_mem_put(resolver->mctx, algorithms,
*algorithms);
@ -9451,6 +9612,11 @@ dns_resolver_disable_ds_digest(dns_resolver_t *resolver, dns_name_t *name,
isc_result_t result;
dns_rbtnode_t *node = NULL;
/*
* Whether a digest is disabled (or not) is stored in a per-name
* bitfield that is stored as the node data of an RBT.
*/
REQUIRE(VALID_RESOLVER(resolver));
if (digest_type > 255)
return (ISC_R_RANGE);
@ -9472,7 +9638,14 @@ dns_resolver_disable_ds_digest(dns_resolver_t *resolver, dns_name_t *name,
if (result == ISC_R_SUCCESS || result == ISC_R_EXISTS) {
digests = node->data;
/* If digests is set, digests[0] contains its length. */
if (digests == NULL || len > *digests) {
/*
* If no bitfield exists in the node data, or if
* it is not long enough, allocate a new
* bitfield and copy the old (smaller) bitfield
* into it if one exists.
*/
new = isc_mem_get(resolver->mctx, len);
if (new == NULL) {
result = ISC_R_NOMEMORY;
@ -9482,8 +9655,10 @@ dns_resolver_disable_ds_digest(dns_resolver_t *resolver, dns_name_t *name,
if (digests != NULL)
memmove(new, digests, *digests);
new[len-1] |= mask;
/* new[0] should contain the length of new. */
*new = len;
node->data = new;
/* Free the older bitfield. */
if (digests != NULL)
isc_mem_put(resolver->mctx, digests,
*digests);

View File

@ -136,8 +136,8 @@ load_geoip(const char *dir) {
}
static isc_boolean_t
do_lookup_string(const char *addr, dns_geoip_subtype_t subtype,
const char *string)
do_lookup_string(const char *addr, isc_uint8_t *scope,
dns_geoip_subtype_t subtype, const char *string)
{
dns_geoip_elem_t elt;
struct in_addr in4;
@ -149,12 +149,12 @@ do_lookup_string(const char *addr, dns_geoip_subtype_t subtype,
elt.subtype = subtype;
strcpy(elt.as_string, string);
return (dns_geoip_match(&na, &geoip, &elt));
return (dns_geoip_match(&na, scope, &geoip, &elt));
}
static isc_boolean_t
do_lookup_string_v6(const char *addr, dns_geoip_subtype_t subtype,
const char *string)
do_lookup_string_v6(const char *addr, isc_uint8_t *scope,
dns_geoip_subtype_t subtype, const char *string)
{
dns_geoip_elem_t elt;
struct in6_addr in6;
@ -166,11 +166,13 @@ do_lookup_string_v6(const char *addr, dns_geoip_subtype_t subtype,
elt.subtype = subtype;
strcpy(elt.as_string, string);
return (dns_geoip_match(&na, &geoip, &elt));
return (dns_geoip_match(&na, scope, &geoip, &elt));
}
static isc_boolean_t
do_lookup_int(const char *addr, dns_geoip_subtype_t subtype, int id) {
do_lookup_int(const char *addr, isc_uint8_t *scope,
dns_geoip_subtype_t subtype, int id)
{
dns_geoip_elem_t elt;
struct in_addr in4;
isc_netaddr_t na;
@ -181,7 +183,7 @@ do_lookup_int(const char *addr, dns_geoip_subtype_t subtype, int id) {
elt.subtype = subtype;
elt.as_int = id;
return (dns_geoip_match(&na, &geoip, &elt));
return (dns_geoip_match(&na, scope, &geoip, &elt));
}
/*
@ -196,6 +198,7 @@ ATF_TC_HEAD(country, tc) {
ATF_TC_BODY(country, tc) {
isc_result_t result;
isc_boolean_t match;
isc_uint8_t scope;
UNUSED(tc);
@ -210,16 +213,30 @@ ATF_TC_BODY(country, tc) {
atf_tc_skip("Database not available");
}
match = do_lookup_string("10.53.0.1", dns_geoip_country_code, "AU");
match = do_lookup_string("10.53.0.1", &scope,
dns_geoip_country_code, "AU");
ATF_CHECK(match);
ATF_CHECK_EQ(scope, 32);
match = do_lookup_string("10.53.0.1",
match = do_lookup_string("10.53.0.1", &scope,
dns_geoip_country_code3, "AUS");
ATF_CHECK(match);
ATF_CHECK_EQ(scope, 32);
match = do_lookup_string("10.53.0.1",
match = do_lookup_string("10.53.0.1", &scope,
dns_geoip_country_name, "Australia");
ATF_CHECK(match);
ATF_CHECK_EQ(scope, 32);
match = do_lookup_string("192.0.2.128", &scope,
dns_geoip_country_code, "O1");
ATF_CHECK(match);
ATF_CHECK_EQ(scope, 24);
match = do_lookup_string("192.0.2.128", &scope,
dns_geoip_country_name, "Other");
ATF_CHECK(match);
ATF_CHECK_EQ(scope, 24);
dns_test_end();
}
@ -232,6 +249,7 @@ ATF_TC_HEAD(country_v6, tc) {
ATF_TC_BODY(country_v6, tc) {
isc_result_t result;
isc_boolean_t match;
isc_uint8_t scope;
UNUSED(tc);
@ -246,17 +264,20 @@ ATF_TC_BODY(country_v6, tc) {
atf_tc_skip("Database not available");
}
match = do_lookup_string_v6("fd92:7065:b8e:ffff::1",
match = do_lookup_string_v6("fd92:7065:b8e:ffff::1", &scope,
dns_geoip_country_code, "AU");
ATF_CHECK(match);
ATF_CHECK_EQ(scope, 128);
match = do_lookup_string_v6("fd92:7065:b8e:ffff::1",
match = do_lookup_string_v6("fd92:7065:b8e:ffff::1", &scope,
dns_geoip_country_code3, "AUS");
ATF_CHECK(match);
ATF_CHECK_EQ(scope, 128);
match = do_lookup_string_v6("fd92:7065:b8e:ffff::1",
match = do_lookup_string_v6("fd92:7065:b8e:ffff::1", &scope,
dns_geoip_country_name, "Australia");
ATF_CHECK(match);
ATF_CHECK_EQ(scope, 128);
dns_test_end();
}
@ -283,42 +304,42 @@ ATF_TC_BODY(city, tc) {
atf_tc_skip("Database not available");
}
match = do_lookup_string("10.53.0.1",
match = do_lookup_string("10.53.0.1", NULL,
dns_geoip_city_continentcode, "NA");
ATF_CHECK(match);
match = do_lookup_string("10.53.0.1",
match = do_lookup_string("10.53.0.1", NULL,
dns_geoip_city_countrycode, "US");
ATF_CHECK(match);
match = do_lookup_string("10.53.0.1",
match = do_lookup_string("10.53.0.1", NULL,
dns_geoip_city_countrycode3, "USA");
ATF_CHECK(match);
match = do_lookup_string("10.53.0.1",
match = do_lookup_string("10.53.0.1", NULL,
dns_geoip_city_countryname, "United States");
ATF_CHECK(match);
match = do_lookup_string("10.53.0.1",
match = do_lookup_string("10.53.0.1", NULL,
dns_geoip_city_region, "CA");
ATF_CHECK(match);
match = do_lookup_string("10.53.0.1",
match = do_lookup_string("10.53.0.1", NULL,
dns_geoip_city_regionname, "California");
ATF_CHECK(match);
match = do_lookup_string("10.53.0.1",
match = do_lookup_string("10.53.0.1", NULL,
dns_geoip_city_name, "Redwood City");
ATF_CHECK(match);
match = do_lookup_string("10.53.0.1",
match = do_lookup_string("10.53.0.1", NULL,
dns_geoip_city_postalcode, "94063");
ATF_CHECK(match);
match = do_lookup_int("10.53.0.1", dns_geoip_city_areacode, 650);
match = do_lookup_int("10.53.0.1", NULL, dns_geoip_city_areacode, 650);
ATF_CHECK(match);
match = do_lookup_int("10.53.0.1", dns_geoip_city_metrocode, 807);
match = do_lookup_int("10.53.0.1", NULL, dns_geoip_city_metrocode, 807);
ATF_CHECK(match);
dns_test_end();
@ -346,36 +367,36 @@ ATF_TC_BODY(city_v6, tc) {
atf_tc_skip("Database not available");
}
match = do_lookup_string_v6("fd92:7065:b8e:ffff::1",
match = do_lookup_string_v6("fd92:7065:b8e:ffff::1", NULL,
dns_geoip_city_continentcode, "NA");
ATF_CHECK(match);
match = do_lookup_string_v6("fd92:7065:b8e:ffff::1",
match = do_lookup_string_v6("fd92:7065:b8e:ffff::1", NULL,
dns_geoip_city_countrycode, "US");
ATF_CHECK(match);
match = do_lookup_string_v6("fd92:7065:b8e:ffff::1",
match = do_lookup_string_v6("fd92:7065:b8e:ffff::1", NULL,
dns_geoip_city_countrycode3, "USA");
ATF_CHECK(match);
match = do_lookup_string_v6("fd92:7065:b8e:ffff::1",
match = do_lookup_string_v6("fd92:7065:b8e:ffff::1", NULL,
dns_geoip_city_countryname,
"United States");
ATF_CHECK(match);
match = do_lookup_string_v6("fd92:7065:b8e:ffff::1",
match = do_lookup_string_v6("fd92:7065:b8e:ffff::1", NULL,
dns_geoip_city_region, "CA");
ATF_CHECK(match);
match = do_lookup_string_v6("fd92:7065:b8e:ffff::1",
match = do_lookup_string_v6("fd92:7065:b8e:ffff::1", NULL,
dns_geoip_city_regionname, "California");
ATF_CHECK(match);
match = do_lookup_string_v6("fd92:7065:b8e:ffff::1",
match = do_lookup_string_v6("fd92:7065:b8e:ffff::1", NULL,
dns_geoip_city_name, "Redwood City");
ATF_CHECK(match);
match = do_lookup_string_v6("fd92:7065:b8e:ffff::1",
match = do_lookup_string_v6("fd92:7065:b8e:ffff::1", NULL,
dns_geoip_city_postalcode, "94063");
ATF_CHECK(match);
@ -405,15 +426,15 @@ ATF_TC_BODY(region, tc) {
atf_tc_skip("Database not available");
}
match = do_lookup_string("10.53.0.1",
match = do_lookup_string("10.53.0.1", NULL,
dns_geoip_region_code, "CA");
ATF_CHECK(match);
match = do_lookup_string("10.53.0.1",
match = do_lookup_string("10.53.0.1", NULL,
dns_geoip_region_name, "California");
ATF_CHECK(match);
match = do_lookup_string("10.53.0.1",
match = do_lookup_string("10.53.0.1", NULL,
dns_geoip_region_countrycode, "US");
ATF_CHECK(match);
@ -447,30 +468,30 @@ ATF_TC_BODY(best, tc) {
atf_tc_skip("Database not available");
}
match = do_lookup_string("10.53.0.4",
match = do_lookup_string("10.53.0.4", NULL,
dns_geoip_countrycode, "US");
ATF_CHECK(match);
match = do_lookup_string("10.53.0.4",
match = do_lookup_string("10.53.0.4", NULL,
dns_geoip_countrycode3, "USA");
ATF_CHECK(match);
match = do_lookup_string("10.53.0.4",
match = do_lookup_string("10.53.0.4", NULL,
dns_geoip_countryname, "United States");
ATF_CHECK(match);
match = do_lookup_string("10.53.0.4",
match = do_lookup_string("10.53.0.4", NULL,
dns_geoip_regionname, "Virginia");
ATF_CHECK(match);
match = do_lookup_string("10.53.0.4",
match = do_lookup_string("10.53.0.4", NULL,
dns_geoip_region, "VA");
ATF_CHECK(match);
GeoIP_delete(geoip.city_v4);
geoip.city_v4 = NULL;
match = do_lookup_string("10.53.0.4",
match = do_lookup_string("10.53.0.4", NULL,
dns_geoip_countrycode, "AU");
ATF_CHECK(match);
@ -478,26 +499,26 @@ ATF_TC_BODY(best, tc) {
* Note, region doesn't support code3 or countryname, so
* the next two would be answered from the country database instead
*/
match = do_lookup_string("10.53.0.4",
match = do_lookup_string("10.53.0.4", NULL,
dns_geoip_countrycode3, "CAN");
ATF_CHECK(match);
match = do_lookup_string("10.53.0.4",
match = do_lookup_string("10.53.0.4", NULL,
dns_geoip_countryname, "Canada");
ATF_CHECK(match);
GeoIP_delete(geoip.region);
geoip.region = NULL;
match = do_lookup_string("10.53.0.4",
match = do_lookup_string("10.53.0.4", NULL,
dns_geoip_countrycode, "CA");
ATF_CHECK(match);
match = do_lookup_string("10.53.0.4",
match = do_lookup_string("10.53.0.4", NULL,
dns_geoip_countrycode3, "CAN");
ATF_CHECK(match);
match = do_lookup_string("10.53.0.4",
match = do_lookup_string("10.53.0.4", NULL,
dns_geoip_countryname, "Canada");
ATF_CHECK(match);
@ -528,7 +549,7 @@ ATF_TC_BODY(asnum, tc) {
}
match = do_lookup_string("10.53.0.3", dns_geoip_as_asnum,
match = do_lookup_string("10.53.0.3", NULL, dns_geoip_as_asnum,
"AS100003 Three Network Labs");
ATF_CHECK(match);
@ -557,7 +578,7 @@ ATF_TC_BODY(isp, tc) {
atf_tc_skip("Database not available");
}
match = do_lookup_string("10.53.0.1", dns_geoip_isp_name,
match = do_lookup_string("10.53.0.1", NULL, dns_geoip_isp_name,
"One Systems, Inc.");
ATF_CHECK(match);
@ -586,7 +607,7 @@ ATF_TC_BODY(org, tc) {
atf_tc_skip("Database not available");
}
match = do_lookup_string("10.53.0.2", dns_geoip_org_name,
match = do_lookup_string("10.53.0.2", NULL, dns_geoip_org_name,
"Two Technology Ltd.");
ATF_CHECK(match);
@ -615,7 +636,7 @@ ATF_TC_BODY(domain, tc) {
atf_tc_skip("Database not available");
}
match = do_lookup_string("10.53.0.4",
match = do_lookup_string("10.53.0.4", NULL,
dns_geoip_domain_name, "four.com");
ATF_CHECK(match);
@ -644,16 +665,16 @@ ATF_TC_BODY(netspeed, tc) {
atf_tc_skip("Database not available");
}
match = do_lookup_int("10.53.0.1", dns_geoip_netspeed_id, 0);
match = do_lookup_int("10.53.0.1", NULL, dns_geoip_netspeed_id, 0);
ATF_CHECK(match);
match = do_lookup_int("10.53.0.2", dns_geoip_netspeed_id, 1);
match = do_lookup_int("10.53.0.2", NULL, dns_geoip_netspeed_id, 1);
ATF_CHECK(match);
match = do_lookup_int("10.53.0.3", dns_geoip_netspeed_id, 2);
match = do_lookup_int("10.53.0.3", NULL, dns_geoip_netspeed_id, 2);
ATF_CHECK(match);
match = do_lookup_int("10.53.0.4", dns_geoip_netspeed_id, 3);
match = do_lookup_int("10.53.0.4", NULL, dns_geoip_netspeed_id, 3);
ATF_CHECK(match);
dns_test_end();

View File

@ -25,9 +25,11 @@ dns_acl_isany
dns_acl_isinsecure
dns_acl_isnone
dns_acl_match
dns_acl_match2
dns_acl_merge
dns_acl_none
dns_aclelement_match
dns_aclelement_match2
dns_aclenv_copy
dns_aclenv_destroy
dns_aclenv_init

View File

@ -14,8 +14,6 @@
* PERFORMANCE OF THIS SOFTWARE.
*/
/* $Id: radix.h,v 1.13 2008/12/01 23:47:45 tbox Exp $ */
/*
* This source was adapted from MRT's RCS Ids:
* Id: radix.h,v 1.6 1999/08/03 03:32:53 masaki Exp
@ -34,7 +32,7 @@
#ifndef _RADIX_H
#define _RADIX_H
#define NETADDR_TO_PREFIX_T(na,pt,bits) \
#define NETADDR_TO_PREFIX_T(na,pt,bits,isecs) \
do { \
memset(&(pt), 0, sizeof(pt)); \
if((na) != NULL) { \
@ -50,6 +48,7 @@
(pt).family = AF_UNSPEC; \
(pt).bitlen = 0; \
} \
(pt).ecs = isecs; \
isc_refcount_init(&(pt).refcount, 0); \
} while(0)
@ -57,6 +56,7 @@ typedef struct isc_prefix {
isc_mem_t *mctx;
unsigned int family; /* AF_INET | AF_INET6, or AF_UNSPEC for "any" */
unsigned int bitlen; /* 0 for "any" */
isc_boolean_t ecs; /* ISC_TRUE for an EDNS client subnet address */
isc_refcount_t refcount;
union {
struct in_addr sin;
@ -81,23 +81,32 @@ typedef void (*isc_radix_processfunc_t)(isc_prefix_t *, void **);
* return the one that was added first.
*
* An IPv4 prefix and an IPv6 prefix may share a radix tree node if they
* have the same length and bit pattern (e.g., 127/8 and 7f::/8). To
* disambiguate between them, node_num and data are two-element arrays;
* node_num[0] and data[0] are used for IPv4 addresses, node_num[1]
* and data[1] for IPv6 addresses. The only exception is a prefix of
* 0/0 (aka "any" or "none"), which is always stored as IPv4 but matches
* IPv6 addresses too.
* have the same length and bit pattern (e.g., 127/8 and 7f::/8). Also,
* a node that matches a client address may also match an EDNS client
* subnet address. To disambiguate between these, node_num and data
* are four-element arrays;
*
* - node_num[0] and data[0] are used for IPv4 client addresses
* - node_num[1] and data[1] for IPv4 client subnet addresses
* - node_num[2] and data[2] are used for IPv6 client addresses
* - node_num[3] and data[3] for IPv6 client subnet addresses
*
* A prefix of 0/0 (aka "any" or "none"), is always stored as IPv4,
* but matches IPv6 addresses too, as well as all client subnet
* addresses.
*/
#define ISC_IS6(family) ((family) == AF_INET6 ? 1 : 0)
#define ISC_RADIX_OFF(p) \
((((p)->family == AF_INET6) ? 1 : 0) + ((p)->ecs ? 2 : 0))
typedef struct isc_radix_node {
isc_mem_t *mctx;
isc_uint32_t bit; /* bit length of the prefix */
isc_prefix_t *prefix; /* who we are in radix tree */
struct isc_radix_node *l, *r; /* left and right children */
struct isc_radix_node *parent; /* may be used */
void *data[2]; /* pointers to IPv4 and IPV6 data */
int node_num[2]; /* which node this was in the tree,
void *data[4]; /* pointers to IPv4 and IPV6 data */
int node_num[4]; /* which node this was in the tree,
or -1 for glue nodes */
} isc_radix_node_t;

View File

@ -70,6 +70,7 @@ _new_prefix(isc_mem_t *mctx, isc_prefix_t **target, int family, void *dest,
}
prefix->family = family;
prefix->ecs = ISC_FALSE;
prefix->mctx = NULL;
isc_mem_attach(mctx, &prefix->mctx);
@ -182,12 +183,13 @@ _clear_radix(isc_radix_tree_t *radix, isc_radix_destroyfunc_t func) {
if (Xrn->prefix != NULL) {
_deref_prefix(Xrn->prefix);
if (func != NULL && (Xrn->data[0] != NULL ||
Xrn->data[1] != NULL))
if (func != NULL)
func(Xrn->data);
} else {
INSIST(Xrn->data[0] == NULL &&
Xrn->data[1] == NULL);
Xrn->data[1] == NULL &&
Xrn->data[2] == NULL &&
Xrn->data[3] == NULL);
}
isc_mem_put(radix->mctx, Xrn, sizeof(*Xrn));
@ -242,8 +244,7 @@ isc_radix_search(isc_radix_tree_t *radix, isc_radix_node_t **target,
isc_radix_node_t *stack[RADIX_MAXBITS + 1];
u_char *addr;
isc_uint32_t bitlen;
int tfamily = -1;
int cnt = 0;
int toff = -1, cnt = 0;
REQUIRE(radix != NULL);
REQUIRE(prefix != NULL);
@ -281,13 +282,15 @@ isc_radix_search(isc_radix_tree_t *radix, isc_radix_node_t **target,
if (_comp_with_mask(isc_prefix_tochar(node->prefix),
isc_prefix_tochar(prefix),
node->prefix->bitlen)) {
if (node->node_num[ISC_IS6(prefix->family)] != -1 &&
((*target == NULL) ||
(*target)->node_num[ISC_IS6(tfamily)] >
node->node_num[ISC_IS6(prefix->family)])) {
node->prefix->bitlen))
{
int off = ISC_RADIX_OFF(prefix);
if (node->node_num[off] != -1 &&
((*target == NULL) ||
(*target)->node_num[toff] > node->node_num[off]))
{
*target = node;
tfamily = prefix->family;
toff = off;
}
}
}
@ -327,7 +330,8 @@ isc_radix_insert(isc_radix_tree_t *radix, isc_radix_node_t **target,
if (node == NULL)
return (ISC_R_NOMEMORY);
node->bit = bitlen;
node->node_num[0] = node->node_num[1] = -1;
for (i = 0; i < 4; i++)
node->node_num[i] = -1;
node->prefix = NULL;
result = _ref_prefix(radix->mctx, &node->prefix, prefix);
if (result != ISC_R_SUCCESS) {
@ -346,25 +350,24 @@ isc_radix_insert(isc_radix_tree_t *radix, isc_radix_node_t **target,
* added to num_added_node at the end of
* the merge operation--we don't do it here.
*/
if (source->node_num[0] != -1)
node->node_num[0] = radix->num_added_node +
source->node_num[0];
if (source->node_num[1] != -1)
node->node_num[1] = radix->num_added_node +
source->node_num[1];
node->data[0] = source->data[0];
node->data[1] = source->data[1];
for (i = 0; i < 4; i++) {
if (source->node_num[i] != -1)
node->node_num[i] =
radix->num_added_node +
source->node_num[i];
node->data[i] = source->data[i];
}
} else {
int next = ++radix->num_added_node;
if (fam == AF_UNSPEC) {
/* "any" or "none" */
node->node_num[0] = node->node_num[1] =
++radix->num_added_node;
for (i = 0; i < 4; i++)
node->node_num[i] = next;
} else {
node->node_num[ISC_IS6(fam)] =
++radix->num_added_node;
node->node_num[ISC_RADIX_OFF(prefix)] = next;
}
node->data[0] = NULL;
node->data[1] = NULL;
memset(node->data, 0, sizeof(node->data));
}
radix->head = node;
radix->num_active_node++;
@ -426,37 +429,33 @@ isc_radix_insert(isc_radix_tree_t *radix, isc_radix_node_t **target,
if (node->prefix != NULL) {
/* Set node_num only if it hasn't been set before */
if (source != NULL) {
/* Merging node */
if (node->node_num[0] == -1 &&
source->node_num[0] != -1) {
node->node_num[0] =
radix->num_added_node +
source->node_num[0];
node->data[0] = source->data[0];
}
if (node->node_num[1] == -1 &&
source->node_num[0] != -1) {
node->node_num[1] =
radix->num_added_node +
source->node_num[1];
node->data[1] = source->data[1];
/* Merging nodes */
for (i = 0; i < 4; i++) {
if (node->node_num[i] == -1 &&
source->node_num[i] != -1) {
node->node_num[i] =
radix->num_added_node +
source->node_num[i];
node->data[i] = source->data[i];
}
}
} else {
if (fam == AF_UNSPEC) {
/* "any" or "none" */
int next = radix->num_added_node + 1;
if (node->node_num[0] == -1) {
node->node_num[0] = next;
radix->num_added_node = next;
}
if (node->node_num[1] == -1) {
node->node_num[1] = next;
radix->num_added_node = next;
for (i = 0; i < 4; i++) {
if (node->node_num[i] == -1) {
node->node_num[i] =
next;
radix->num_added_node =
next;
}
}
} else {
if (node->node_num[ISC_IS6(fam)] == -1)
node->node_num[ISC_IS6(fam)]
= ++radix->num_added_node;
int off = ISC_RADIX_OFF(prefix);
if (node->node_num[off] == -1)
node->node_num[off] =
++radix->num_added_node;
}
}
*target = node;
@ -468,27 +467,27 @@ isc_radix_insert(isc_radix_tree_t *radix, isc_radix_node_t **target,
return (result);
}
INSIST(node->data[0] == NULL && node->node_num[0] == -1 &&
node->data[1] == NULL && node->node_num[1] == -1);
node->data[1] == NULL && node->node_num[1] == -1 &&
node->data[2] == NULL && node->node_num[2] == -1 &&
node->data[3] == NULL && node->node_num[3] == -1);
if (source != NULL) {
/* Merging node */
if (source->node_num[0] != -1) {
node->node_num[0] = radix->num_added_node +
source->node_num[0];
node->data[0] = source->data[0];
}
if (source->node_num[1] != -1) {
node->node_num[1] = radix->num_added_node +
source->node_num[1];
node->data[1] = source->data[1];
for (i = 0; i < 4; i++) {
int cur = radix->num_added_node;
if (source->node_num[i] != -1) {
node->node_num[i] =
source->node_num[i] + cur;
node->data[i] = source->data[i];
}
}
} else {
int next = ++radix->num_added_node;
if (fam == AF_UNSPEC) {
/* "any" or "none" */
node->node_num[0] = node->node_num[1] =
++radix->num_added_node;
for (i = 0; i < 4; i++)
node->node_num[i] = next;
} else {
node->node_num[ISC_IS6(fam)] =
++radix->num_added_node;
node->node_num[ISC_RADIX_OFF(prefix)] = next;
}
}
*target = node;
@ -518,30 +517,30 @@ isc_radix_insert(isc_radix_tree_t *radix, isc_radix_node_t **target,
}
new_node->parent = NULL;
new_node->l = new_node->r = NULL;
new_node->node_num[0] = new_node->node_num[1] = -1;
for (i = 0; i < 4; i++)
new_node->node_num[i] = -1;
radix->num_active_node++;
if (source != NULL) {
/* Merging node */
if (source->node_num[0] != -1)
new_node->node_num[0] = radix->num_added_node +
source->node_num[0];
if (source->node_num[1] != -1)
new_node->node_num[1] = radix->num_added_node +
source->node_num[1];
new_node->data[0] = source->data[0];
new_node->data[1] = source->data[1];
for (i = 0; i < 4; i++) {
int cur = radix->num_added_node;
if (source->node_num[i] != -1) {
new_node->node_num[i] =
source->node_num[i] + cur;
new_node->data[i] = source->data[i];
}
}
} else {
int next = ++radix->num_added_node;
if (fam == AF_UNSPEC) {
/* "any" or "none" */
new_node->node_num[0] = new_node->node_num[1] =
++radix->num_added_node;
for (i = 0; i < 4; i++)
new_node->node_num[i] = next;
} else {
new_node->node_num[ISC_IS6(fam)] =
++radix->num_added_node;
new_node->node_num[ISC_RADIX_OFF(prefix)] = next;
}
new_node->data[0] = NULL;
new_node->data[1] = NULL;
memset(new_node->data, 0, sizeof(new_node->data));
}
if (node->bit == differ_bit) {
@ -583,8 +582,10 @@ isc_radix_insert(isc_radix_tree_t *radix, isc_radix_node_t **target,
glue->bit = differ_bit;
glue->prefix = NULL;
glue->parent = node->parent;
glue->data[0] = glue->data[1] = NULL;
glue->node_num[0] = glue->node_num[1] = -1;
for (i = 0; i < 4; i++) {
glue->data[i] = NULL;
glue->node_num[i] = -1;
}
radix->num_active_node++;
if (differ_bit < radix->maxbits &&
BIT_TEST(addr[differ_bit>>3], 0x80 >> (differ_bit & 07))) {
@ -627,7 +628,7 @@ isc_radix_remove(isc_radix_tree_t *radix, isc_radix_node_t *node) {
_deref_prefix(node->prefix);
node->prefix = NULL;
node->data[0] = node->data[1] = NULL;
memset(node->data, 0, sizeof(node->data));
return;
}

View File

@ -482,6 +482,7 @@ parse_geoip_element(const cfg_obj_t *obj, isc_log_t *lctx,
const char *stype, *search;
dns_geoip_subtype_t subtype;
dns_aclelement_t de;
size_t len;
REQUIRE(dep != NULL);
@ -493,35 +494,52 @@ parse_geoip_element(const cfg_obj_t *obj, isc_log_t *lctx,
stype = cfg_obj_asstring(cfg_tuple_get(obj, "subtype"));
search = cfg_obj_asstring(cfg_tuple_get(obj, "search"));
len = strlen(search);
if (strcasecmp(stype, "country") == 0 && strlen(search) == 2) {
if (len == 0) {
cfg_obj_log(obj, lctx, ISC_LOG_ERROR,
"zero-length geoip search field");
return (ISC_R_FAILURE);
}
if (strcasecmp(stype, "country") == 0 && len == 2) {
/* Two-letter country code */
subtype = dns_geoip_countrycode;
strncpy(de.geoip_elem.as_string, search, 2);
} else if (strcasecmp(stype, "country") == 0 && strlen(search) == 3) {
strlcpy(de.geoip_elem.as_string, search,
sizeof(de.geoip_elem.as_string));
} else if (strcasecmp(stype, "country") == 0 && len == 3) {
/* Three-letter country code */
subtype = dns_geoip_countrycode3;
strncpy(de.geoip_elem.as_string, search, 3);
strlcpy(de.geoip_elem.as_string, search,
sizeof(de.geoip_elem.as_string));
} else if (strcasecmp(stype, "country") == 0) {
/* Country name */
subtype = dns_geoip_countryname;
strncpy(de.geoip_elem.as_string, search, 255);
} else if (strcasecmp(stype, "region") == 0 && strlen(search) == 2) {
strlcpy(de.geoip_elem.as_string, search,
sizeof(de.geoip_elem.as_string));
} else if (strcasecmp(stype, "region") == 0 && len == 2) {
/* Two-letter region code */
subtype = dns_geoip_region;
strncpy(de.geoip_elem.as_string, search, 2);
strlcpy(de.geoip_elem.as_string, search,
sizeof(de.geoip_elem.as_string));
} else if (strcasecmp(stype, "region") == 0) {
/* Region name */
subtype = dns_geoip_regionname;
strncpy(de.geoip_elem.as_string, search, 255);
strlcpy(de.geoip_elem.as_string, search,
sizeof(de.geoip_elem.as_string));
} else if (strcasecmp(stype, "city") == 0) {
/* City name */
subtype = dns_geoip_city_name;
strncpy(de.geoip_elem.as_string, search, 255);
} else if (strcasecmp(stype, "postal") == 0 && strlen(search) < 7) {
strlcpy(de.geoip_elem.as_string, search,
sizeof(de.geoip_elem.as_string));
} else if (strcasecmp(stype, "postal") == 0 && len < 7) {
subtype = dns_geoip_city_postalcode;
strncpy(de.geoip_elem.as_string, search, 6);
de.geoip_elem.as_string[6] = '\0';
strlcpy(de.geoip_elem.as_string, search,
sizeof(de.geoip_elem.as_string));
} else if (strcasecmp(stype, "postal") == 0) {
cfg_obj_log(obj, lctx, ISC_LOG_ERROR,
"geoiop postal code (%s) too long", search);
return (ISC_R_FAILURE);
} else if (strcasecmp(stype, "metro") == 0) {
subtype = dns_geoip_city_metrocode;
de.geoip_elem.as_int = atoi(search);
@ -530,23 +548,33 @@ parse_geoip_element(const cfg_obj_t *obj, isc_log_t *lctx,
de.geoip_elem.as_int = atoi(search);
} else if (strcasecmp(stype, "tz") == 0) {
subtype = dns_geoip_city_timezonecode;
strncpy(de.geoip_elem.as_string, search, 255);
} else if (strcasecmp(stype, "continent") == 0 && strlen(search) == 2) {
strlcpy(de.geoip_elem.as_string, search,
sizeof(de.geoip_elem.as_string));
} else if (strcasecmp(stype, "continent") == 0 && len == 2) {
/* Two-letter continent code */
subtype = dns_geoip_city_continentcode;
strncpy(de.geoip_elem.as_string, search, 2);
strlcpy(de.geoip_elem.as_string, search,
sizeof(de.geoip_elem.as_string));
} else if (strcasecmp(stype, "continent") == 0) {
cfg_obj_log(obj, lctx, ISC_LOG_ERROR,
"geoiop continent code (%s) too long", search);
return (ISC_R_FAILURE);
} else if (strcasecmp(stype, "isp") == 0) {
subtype = dns_geoip_isp_name;
strncpy(de.geoip_elem.as_string, search, 255);
strlcpy(de.geoip_elem.as_string, search,
sizeof(de.geoip_elem.as_string));
} else if (strcasecmp(stype, "asnum") == 0) {
subtype = dns_geoip_as_asnum;
strncpy(de.geoip_elem.as_string, search, 255);
strlcpy(de.geoip_elem.as_string, search,
sizeof(de.geoip_elem.as_string));
} else if (strcasecmp(stype, "org") == 0) {
subtype = dns_geoip_org_name;
strncpy(de.geoip_elem.as_string, search, 255);
strlcpy(de.geoip_elem.as_string, search,
sizeof(de.geoip_elem.as_string));
} else if (strcasecmp(stype, "domain") == 0) {
subtype = dns_geoip_domain_name;
strncpy(de.geoip_elem.as_string, search, 255);
strlcpy(de.geoip_elem.as_string, search,
sizeof(de.geoip_elem.as_string));
} else if (strcasecmp(stype, "netspeed") == 0) {
subtype = dns_geoip_netspeed_id;
de.geoip_elem.as_int = atoi(search);
@ -668,6 +696,7 @@ cfg_acl_fromconfig2(const cfg_obj_t *caml, const cfg_obj_t *cctx,
/* Network prefix */
isc_netaddr_t addr;
unsigned int bitlen;
isc_boolean_t setpos, setecs;
cfg_obj_asnetprefix(ce, &addr, &bitlen);
if (family != 0 && family != addr.family) {
@ -685,8 +714,10 @@ cfg_acl_fromconfig2(const cfg_obj_t *caml, const cfg_obj_t *cctx,
* If nesting ACLs (nest_level != 0), we negate
* the nestedacl element, not the iptable entry.
*/
result = dns_iptable_addprefix(iptab, &addr, bitlen,
ISC_TF(nest_level != 0 || !neg));
setpos = ISC_TF(nest_level != 0 || !neg);
setecs = cfg_obj_istype(ce, &cfg_type_ecsprefix);
result = dns_iptable_addprefix2(iptab, &addr, bitlen,
setpos, setecs);
if (result != ISC_R_SUCCESS)
goto cleanup;

View File

@ -54,4 +54,7 @@ LIBISCCFG_EXTERNAL_DATA extern cfg_type_t cfg_type_sessionkey;
LIBISCCFG_EXTERNAL_DATA extern cfg_type_t cfg_type_keyref;
/*%< A key reference, used as an ACL element */
/*%< An EDNS client subnet address, used as an ACL element */
LIBISCCFG_EXTERNAL_DATA extern cfg_type_t cfg_type_ecsprefix;
#endif /* ISCCFG_NAMEDCONF_H */

View File

@ -950,9 +950,12 @@ options_clauses[] = {
{ "flush-zones-on-shutdown", &cfg_type_boolean, 0 },
#ifdef HAVE_GEOIP
{ "geoip-directory", &cfg_type_qstringornone, 0 },
{ "geoip-use-ecs", &cfg_type_boolean, 0 },
#else
{ "geoip-directory", &cfg_type_qstringornone,
CFG_CLAUSEFLAG_NOTCONFIGURED },
{ "geoip-use-ecs", &cfg_type_qstringornone,
CFG_CLAUSEFLAG_NOTCONFIGURED },
#endif /* HAVE_GEOIP */
{ "has-old-clients", &cfg_type_boolean, CFG_CLAUSEFLAG_OBSOLETE },
{ "heartbeat-interval", &cfg_type_uint32, 0 },
@ -2281,6 +2284,16 @@ doc_geoip(cfg_printer_t *pctx, const cfg_type_t *type) {
}
#endif /* HAVE_GEOIP */
/*%
* An EDNS client subnet address
*/
static keyword_type_t ecs_kw = { "ecs", &cfg_type_netprefix };
LIBISCCFG_EXTERNAL_DATA cfg_type_t cfg_type_ecsprefix = {
"edns_client_subnet", parse_keyvalue, print_keyvalue, doc_keyvalue,
&cfg_rep_netprefix, &ecs_kw
};
/*%
* A "controls" statement is represented as a map with the multivalued
* "inet" and "unix" clauses.
@ -2570,6 +2583,9 @@ parse_addrmatchelt(cfg_parser_t *pctx, const cfg_type_t *type, cfg_obj_t **ret)
if (pctx->token.type == isc_tokentype_string &&
(strcasecmp(TOKEN_STRING(pctx), "key") == 0)) {
CHECK(cfg_parse_obj(pctx, &cfg_type_keyref, ret));
} else if (pctx->token.type == isc_tokentype_string &&
(strcasecmp(TOKEN_STRING(pctx), "ecs") == 0)) {
CHECK(cfg_parse_obj(pctx, &cfg_type_ecsprefix, ret));
} else if (pctx->token.type == isc_tokentype_string &&
(strcasecmp(TOKEN_STRING(pctx), "geoip") == 0)) {
#ifdef HAVE_GEOIP

View File

@ -1313,10 +1313,11 @@
./bin/tests/system/geoip/geoip.c C 2013
./bin/tests/system/geoip/ns2/example.db.in ZONE 2013
./bin/tests/system/geoip/ns2/named1.conf CONF-C 2013
./bin/tests/system/geoip/ns2/named10.conf CONF-C 2013
./bin/tests/system/geoip/ns2/named10.conf CONF-C 2014
./bin/tests/system/geoip/ns2/named11.conf CONF-C 2013
./bin/tests/system/geoip/ns2/named12.conf CONF-C 2014
./bin/tests/system/geoip/ns2/named12.conf CONF-C 2013
./bin/tests/system/geoip/ns2/named13.conf CONF-C 2014
./bin/tests/system/geoip/ns2/named14.conf CONF-C 2014
./bin/tests/system/geoip/ns2/named2.conf CONF-C 2013
./bin/tests/system/geoip/ns2/named3.conf CONF-C 2013
./bin/tests/system/geoip/ns2/named4.conf CONF-C 2013