Commit d46855ca authored by Evan Hunt's avatar Evan Hunt

[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]
parent 180319f5
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.,
......
......@@ -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 (allowed(&netaddr, tsig, view->matchclients) &&
allowed(&client->destaddr, tsig,
view->matchdestinations) &&
!((client->message->flags & DNS_MESSAGEFLAG_RD)
== 0 && view->matchrecursiveonly))
if (sigresult == ISC_R_SUCCESS) {
dns_tsigkey_t *tsigkey;
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_max = 52
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 = 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 */
......
/*
* 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; };
};
/*
* 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
......@@ -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 {