[master] ECS authoritative support
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]
This commit is contained in:
21
CHANGES
21
CHANGES
@@ -1,3 +1,24 @@
|
||||
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.,
|
||||
|
||||
6
README
6
README
@@ -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
|
||||
|
||||
@@ -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. */
|
||||
|
||||
@@ -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\
|
||||
|
||||
@@ -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;
|
||||
|
||||
|
||||
@@ -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
|
||||
};
|
||||
|
||||
|
||||
@@ -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 */
|
||||
|
||||
/*
|
||||
|
||||
@@ -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 */
|
||||
|
||||
50
bin/tests/system/acl/ns2/named6.conf
Normal file
50
bin/tests/system/acl/ns2/named6.conf
Normal 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; };
|
||||
};
|
||||
60
bin/tests/system/acl/ns2/named7.conf
Normal file
60
bin/tests/system/acl/ns2/named7.conf
Normal 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";
|
||||
};
|
||||
};
|
||||
@@ -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
|
||||
|
||||
@@ -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.*
|
||||
|
||||
@@ -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
|
||||
|
||||
|
Binary file not shown.
@@ -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
|
||||
|
||||
@@ -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" {
|
||||
|
||||
@@ -24,10 +24,11 @@ options {
|
||||
transfer-source 10.53.0.2;
|
||||
port 5300;
|
||||
pid-file "named.pid";
|
||||
listen-on { 10.53.0.2; };
|
||||
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 {
|
||||
@@ -107,6 +108,6 @@ view none {
|
||||
match-clients { any; };
|
||||
zone "example" {
|
||||
type master;
|
||||
file "example.db.in";
|
||||
file "examplebogus.db";
|
||||
};
|
||||
};
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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,6 +272,20 @@ 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 /'
|
||||
@@ -210,6 +305,20 @@ done
|
||||
[ $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 /'
|
||||
@@ -248,6 +357,20 @@ 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/named13.conf ns2/named.conf
|
||||
$RNDC -c ../common/rndc.conf -s 10.53.0.2 -p 9953 reload 2>&1 | sed 's/^/I:ns2 /'
|
||||
@@ -280,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
|
||||
|
||||
@@ -3444,66 +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 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>
|
||||
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>
|
||||
@@ -4858,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>
|
||||
@@ -6240,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>
|
||||
@@ -16188,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
|
||||
@@ -16202,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>
|
||||
@@ -16239,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>
|
||||
|
||||
139
lib/dns/acl.c
139
lib/dns/acl.c
@@ -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
|
||||
|
||||
125
lib/dns/geoip.c
125
lib/dns/geoip.c
@@ -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,7 +824,7 @@ dns_geoip_match(const isc_netaddr_t *reqaddr,
|
||||
if (family == AF_INET6)
|
||||
return (ISC_FALSE);
|
||||
|
||||
s = name_lookup(db, subtype, ipnum);
|
||||
s = name_lookup(db, subtype, ipnum, scope);
|
||||
if (s != NULL) {
|
||||
size_t l;
|
||||
if (strcasecmp(elt->as_string, s) == 0)
|
||||
@@ -790,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;
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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);
|
||||
|
||||
|
||||
@@ -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
|
||||
*/
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -15,8 +15,6 @@
|
||||
* PERFORMANCE OF THIS SOFTWARE.
|
||||
*/
|
||||
|
||||
/* $Id$ */
|
||||
|
||||
/*! \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();
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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;
|
||||
|
||||
|
||||
165
lib/isc/radix.c
165
lib/isc/radix.c
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
@@ -696,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) {
|
||||
@@ -713,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;
|
||||
|
||||
|
||||
@@ -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 */
|
||||
|
||||
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user