Skip to content

Instantly share code, notes, and snippets.

Show Gist options
  • Save jialeicui/240d1cceecf9956921a3 to your computer and use it in GitHub Desktop.
Save jialeicui/240d1cceecf9956921a3 to your computer and use it in GitHub Desktop.
From 83f0062d385fd4f111b31c1f26b571cabd7e0e4c Mon Sep 17 00:00:00 2001
From: Vincent Bernat <[email protected]>
Date: Thu, 5 Sep 2013 16:52:45 +0200
Subject: [PATCH] EDNS0 client subnet support.
---
bin/named/client.c | 227 +++++++++++++++++++++++++++++++--------
bin/named/include/named/client.h | 4 +
bin/named/include/named/server.h | 81 +++++++-------
bin/named/sortlist.c | 4 +-
bin/named/statschannel.c | 2 +
lib/dns/acl.c | 86 ++++++++++-----
lib/dns/include/dns/acl.h | 18 ++++
7 files changed, 312 insertions(+), 110 deletions(-)
diff --git a/bin/named/client.c b/bin/named/client.c
index 2115ac1..f5db80e 100644
--- a/bin/named/client.c
+++ b/bin/named/client.c
@@ -1188,6 +1188,8 @@ client_addopt(ns_client_t *client) {
dns_view_t *view;
dns_resolver_t *resolver;
isc_uint16_t udpsize;
+ isc_buffer_t *buffer = NULL;
+ char nsid[BUFSIZ], *nsidp = NULL;
REQUIRE(client->opt == NULL); /* XXXRTH free old. */
@@ -1225,6 +1227,20 @@ client_addopt(ns_client_t *client) {
rdatalist->ttl = (client->extflags & DNS_MESSAGEEXTFLAG_REPLYPRESERVE);
/* Set EDNS options if applicable */
+ rdata->data = NULL;
+ rdata->length = 0;
+ if (client->clientaddrlen) {
+ /* Client subnet */
+ /* What to do when scope is 0? If we keep 0, we will
+ * provide an answer valid for any IP address. If we
+ * don't provide a client subnet, all the same. So we
+ * have to do something sensible. We assume that we
+ * did use client subnet. TODO: add a flag to check
+ * that we have a geoenabled view. */
+ if (client->clientscopelen == 0)
+ client->clientscopelen = client->clientaddrlen;
+ rdata->length += 8 + (client->clientaddrlen + 7) / 8;
+ }
if (client->attributes & NS_CLIENTATTR_WANTNSID &&
(ns_g_server->server_id != NULL ||
ns_g_server->server_usehostname)) {
@@ -1234,36 +1250,49 @@ client_addopt(ns_client_t *client) {
* + 2 bytes for NSID length
* + NSID itself
*/
- char nsid[BUFSIZ], *nsidp;
- isc_buffer_t *buffer = NULL;
-
if (ns_g_server->server_usehostname) {
isc_result_t result;
result = ns_os_gethostname(nsid, sizeof(nsid));
- if (result != ISC_R_SUCCESS) {
- goto no_nsid;
+ if (result == ISC_R_SUCCESS) {
+ nsidp = nsid;
}
- nsidp = nsid;
} else
nsidp = ns_g_server->server_id;
- rdata->length = strlen(nsidp) + 4;
- result = isc_buffer_allocate(client->mctx, &buffer,
- rdata->length);
- if (result != ISC_R_SUCCESS)
- goto no_nsid;
-
+ if (nsidp)
+ rdata->length += strlen(nsidp) + 4;
+ }
+
+ result = isc_buffer_allocate(client->mctx, &buffer,
+ rdata->length);
+ if (result != ISC_R_SUCCESS) goto no_opt;
+ if (client->clientaddrlen) {
+ int addrbytes = (client->clientaddrlen + 7) / 8;
+ isc_uint8_t *paddr;
+ int i;
+ isc_buffer_putuint16(buffer, DNS_OPT_CLIENT_SUBNET);
+ isc_buffer_putuint16(buffer, 4 + addrbytes);
+ isc_buffer_putuint16(buffer,
+ (client->clientaddr.family == AF_INET)?1:2);
+ isc_buffer_putuint8(buffer, client->clientaddrlen);
+ isc_buffer_putuint8(buffer, client->clientscopelen);
+ paddr = (isc_uint8_t*)&client->clientaddr.type;
+ for (i = 0; i < addrbytes; i++) {
+ isc_buffer_putuint8(buffer,
+ paddr[i] & ((i == addrbytes - 1 &&
+ (client->clientaddrlen % 8))?
+ (1 << (8 - (client->clientaddrlen % 8))):
+ 0xff));
+ }
+ }
+ if (nsidp) {
isc_buffer_putuint16(buffer, DNS_OPT_NSID);
isc_buffer_putuint16(buffer, strlen(nsidp));
isc_buffer_putstr(buffer, nsidp);
- rdata->data = buffer->base;
- dns_message_takebuffer(client->message, &buffer);
- } else {
-no_nsid:
- rdata->data = NULL;
- rdata->length = 0;
}
-
+ rdata->data = buffer->base;
+ dns_message_takebuffer(client->message, &buffer);
+no_opt:
rdata->rdclass = rdatalist->rdclass;
rdata->type = rdatalist->type;
rdata->flags = 0;
@@ -1279,14 +1308,17 @@ no_nsid:
}
static inline isc_boolean_t
-allowed(isc_netaddr_t *addr, dns_name_t *signer, dns_acl_t *acl) {
+allowed(isc_netaddr_t *addr, isc_netaddr_t *clientaddr,
+ isc_uint8_t *scope,
+ dns_name_t *signer, 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_match_with_client(addr, clientaddr, scope,
+ signer, acl, &ns_g_server->aclenv,
+ &match, NULL);
if (result == ISC_R_SUCCESS && match > 0)
return (ISC_TRUE);
return (ISC_FALSE);
@@ -1349,14 +1381,91 @@ 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, NULL, NULL, tsig, view->matchclients) &&
+ allowed(&netdst, NULL, NULL, tsig, view->matchdestinations))
break;
}
return (ISC_TF(view == myview));
}
/*
+ * Parse EDNS0 client subnet option. `optlen` is the length of the
+ * option after the code and the length. It will be updated to reflect
+ * with what has been read.
+ */
+static isc_result_t
+client_parse_clientsubnet(ns_client_t *client, isc_buffer_t *rdbuf, isc_uint16_t *optlen) {
+ isc_uint16_t family;
+ isc_uint8_t addrlen; /* Source netmask */
+ isc_uint8_t addrbytes;
+ isc_uint8_t scopelen; /* Scope netmask */
+ isc_netaddr_t clientaddr;
+ isc_uint8_t *paddr;
+ int i;
+
+ REQUIRE(NS_CLIENT_VALID(client));
+ REQUIRE(rdbuf != NULL);
+ REQUIRE(optlen != NULL);
+ INSIST(isc_buffer_remaininglength(rdbuf) >= *optlen);
+
+ if (*optlen < 4) {
+ /* 2 octets for family, 1 octet for source netmask and
+ * 1 octet for scope netmask */
+ ns_client_log(client, NS_LOGCATEGORY_CLIENT,
+ NS_LOGMODULE_CLIENT, ISC_LOG_DEBUG(2),
+ "EDNS0 client subnet option is too short");
+ return DNS_R_FORMERR;
+ }
+
+ family = isc_buffer_getuint16(rdbuf);
+ addrlen = isc_buffer_getuint8(rdbuf);
+ scopelen = isc_buffer_getuint8(rdbuf);
+ *optlen -= 4;
+
+ if (scopelen != 0) {
+ ns_client_log(client, NS_LOGCATEGORY_CLIENT,
+ NS_LOGMODULE_CLIENT, ISC_LOG_DEBUG(2),
+ "EDNS0 client subnet scope is not 0");
+ return DNS_R_FORMERR;
+ }
+
+ memset(&clientaddr, 0, sizeof(clientaddr));
+ switch (family) {
+ case 1:
+ /* IPv4 */
+ if (addrlen > 32) addrlen = 32;
+ clientaddr.family = AF_INET;
+ break;
+ case 2:
+ /* IPv6 */
+ if (addrlen > 128) addrlen = 128;
+ clientaddr.family = AF_INET6;
+ break;
+ default:
+ /* Dunno what to do, let's skip all. */
+ return DNS_R_FORMERR;
+ }
+
+ addrbytes = (addrlen + 7) / 8;
+ if (*optlen < addrbytes) {
+ ns_client_log(client, NS_LOGCATEGORY_CLIENT,
+ NS_LOGMODULE_CLIENT, ISC_LOG_DEBUG(2),
+ "EDNS0 client subnet address is too short");
+ return DNS_R_FORMERR;
+ }
+ paddr = (isc_uint8_t*)&clientaddr.type;
+ for (i = 0; i < addrbytes; i++) {
+ paddr[i] = isc_buffer_getuint8(rdbuf);
+ }
+ *optlen -= i;
+
+ memcpy(&client->clientaddr, &clientaddr, sizeof(clientaddr));
+ client->clientaddrlen = addrlen;
+ client->clientscopelen = 0;
+ return ISC_R_SUCCESS;
+}
+
+/*
* Handle an incoming request event from the socket (UDP case)
* or tcpmsg (TCP case).
*/
@@ -1379,6 +1488,7 @@ client_request(isc_task_t *task, isc_event_t *event) {
isc_boolean_t notimp;
dns_rdata_t rdata;
isc_uint16_t optcode;
+ isc_uint16_t optlen;
REQUIRE(event != NULL);
client = event->ev_arg;
@@ -1577,6 +1687,7 @@ client_request(isc_task_t *task, isc_event_t *event) {
/*
* Deal with EDNS.
*/
+ client->clientaddrlen = client->clientscopelen = 0;
opt = dns_message_getopt(client->message);
if (opt != NULL) {
/*
@@ -1612,20 +1723,43 @@ client_request(isc_task_t *task, isc_event_t *event) {
goto cleanup;
}
- /* Check for NSID request */
- result = dns_rdataset_first(opt);
- if (result == ISC_R_SUCCESS) {
+ /* Check for EDNS0 options */
+ for (result = dns_rdataset_first(opt); result == ISC_R_SUCCESS;
+ result = dns_rdataset_next(opt)) {
+ isc_buffer_t rdbuf;
dns_rdata_init(&rdata);
dns_rdataset_current(opt, &rdata);
- if (rdata.length >= 2) {
- isc_buffer_t nsidbuf;
- isc_buffer_init(&nsidbuf,
- rdata.data, rdata.length);
- isc_buffer_add(&nsidbuf, rdata.length);
- optcode = isc_buffer_getuint16(&nsidbuf);
- if (optcode == DNS_OPT_NSID)
+ isc_buffer_init(&rdbuf,
+ rdata.data, rdata.length);
+ isc_buffer_add(&rdbuf, rdata.length);
+ while (isc_buffer_remaininglength(&rdbuf) >= 4) {
+ optcode = isc_buffer_getuint16(&rdbuf);
+ optlen = isc_buffer_getuint16(&rdbuf);
+ if (isc_buffer_remaininglength(&rdbuf) < optlen) {
+ ns_client_log(client, NS_LOGCATEGORY_CLIENT,
+ NS_LOGMODULE_CLIENT, ISC_LOG_DEBUG(2),
+ "EDNS0 option is shorter than expected");
+ ns_client_error(client, DNS_R_FORMERR);
+ goto cleanup;
+ }
+ switch (optcode) {
+ case DNS_OPT_NSID:
client->attributes |=
NS_CLIENTATTR_WANTNSID;
+ break;
+ case DNS_OPT_CLIENT_SUBNET:
+ result = client_parse_clientsubnet(client,
+ &rdbuf,
+ &optlen);
+ if (result != ISC_R_SUCCESS) {
+ ns_client_error(client, result);
+ goto cleanup;
+ }
+ isc_stats_increment(ns_g_server->nsstats,
+ dns_nsstatscounter_subnetclientin);
+ break;
+ }
+ isc__buffer_forward(&rdbuf, optlen);
}
}
@@ -1633,13 +1767,9 @@ client_request(isc_task_t *task, isc_event_t *event) {
dns_nsstatscounter_edns0in);
/*
- * Create an OPT for our reply.
+ * Request an OPT for our reply.
*/
- result = client_addopt(client);
- if (result != ISC_R_SUCCESS) {
- ns_client_error(client, result);
- goto cleanup;
- }
+ client->attributes |= NS_CLIENTATTR_EDNS0;
}
if (client->message->rdclass == 0) {
@@ -1719,8 +1849,11 @@ client_request(isc_task_t *task, isc_event_t *event) {
if (sigresult == ISC_R_SUCCESS)
tsig = dns_tsigkey_identity(client->message->tsigkey);
- if (allowed(&netaddr, tsig, view->matchclients) &&
- allowed(&client->destaddr, tsig,
+ if (allowed(&netaddr,
+ client->clientaddrlen?&client->clientaddr:NULL,
+ client->clientaddrlen?&client->clientscopelen:NULL,
+ tsig, view->matchclients) &&
+ allowed(&client->destaddr, NULL, NULL, tsig,
view->matchdestinations) &&
!((client->message->flags & DNS_MESSAGEFLAG_RD)
== 0 && view->matchrecursiveonly))
@@ -1763,6 +1896,14 @@ client_request(isc_task_t *task, isc_event_t *event) {
NS_LOGMODULE_CLIENT, ISC_LOG_DEBUG(5),
"using view '%s'", view->name);
+ if (client->attributes | NS_CLIENTATTR_EDNS0) {
+ result = client_addopt(client);
+ if (result != ISC_R_SUCCESS) {
+ ns_client_error(client, result);
+ goto cleanup;
+ }
+ }
+
/*
* Check for a signature. We log bad signatures regardless of
* whether they ultimately cause the request to be rejected or
@@ -2109,6 +2250,8 @@ client_create(ns_clientmgr_t *manager, ns_client_t **clientp) {
client->recursionquota = NULL;
client->interface = NULL;
client->peeraddr_valid = ISC_FALSE;
+ client->clientaddrlen = 0;
+ client->clientscopelen = 0;
ISC_EVENT_INIT(&client->ctlevent, sizeof(client->ctlevent), 0, NULL,
NS_EVENT_CLIENTCONTROL, client_start, client, client,
NULL, NULL);
diff --git a/bin/named/include/named/client.h b/bin/named/include/named/client.h
index 33f124d..5eceb2f 100644
--- a/bin/named/include/named/client.h
+++ b/bin/named/include/named/client.h
@@ -139,6 +139,9 @@ struct ns_client {
isc_sockaddr_t peeraddr;
isc_boolean_t peeraddr_valid;
isc_netaddr_t destaddr;
+ isc_netaddr_t clientaddr;
+ isc_uint8_t clientaddrlen;
+ isc_uint8_t clientscopelen;
struct in6_pktinfo pktinfo;
isc_event_t ctlevent;
/*%
@@ -172,6 +175,7 @@ struct ns_client {
#define NS_CLIENTATTR_FILTER_AAAA 0x40 /*%< suppress AAAAs */
#define NS_CLIENTATTR_FILTER_AAAA_RC 0x80 /*%< recursing for A against AAAA */
#endif
+#define NS_CLIENTATTR_EDNS0 0x100 /*%< add an EDNS0 option block in response */
extern unsigned int ns_client_requests;
diff --git a/bin/named/include/named/server.h b/bin/named/include/named/server.h
index 3c6426e..9491e37 100644
--- a/bin/named/include/named/server.h
+++ b/bin/named/include/named/server.h
@@ -126,46 +126,47 @@ enum {
dns_nsstatscounter_requestv4 = 0,
dns_nsstatscounter_requestv6 = 1,
dns_nsstatscounter_edns0in = 2,
- dns_nsstatscounter_badednsver = 3,
- dns_nsstatscounter_tsigin = 4,
- dns_nsstatscounter_sig0in = 5,
- dns_nsstatscounter_invalidsig = 6,
- dns_nsstatscounter_tcp = 7,
-
- dns_nsstatscounter_authrej = 8,
- dns_nsstatscounter_recurserej = 9,
- dns_nsstatscounter_xfrrej = 10,
- dns_nsstatscounter_updaterej = 11,
-
- dns_nsstatscounter_response = 12,
- dns_nsstatscounter_truncatedresp = 13,
- dns_nsstatscounter_edns0out = 14,
- dns_nsstatscounter_tsigout = 15,
- dns_nsstatscounter_sig0out = 16,
-
- dns_nsstatscounter_success = 17,
- dns_nsstatscounter_authans = 18,
- dns_nsstatscounter_nonauthans = 19,
- dns_nsstatscounter_referral = 20,
- dns_nsstatscounter_nxrrset = 21,
- dns_nsstatscounter_servfail = 22,
- dns_nsstatscounter_formerr = 23,
- dns_nsstatscounter_nxdomain = 24,
- dns_nsstatscounter_recursion = 25,
- dns_nsstatscounter_duplicate = 26,
- dns_nsstatscounter_dropped = 27,
- dns_nsstatscounter_failure = 28,
-
- dns_nsstatscounter_xfrdone = 29,
-
- dns_nsstatscounter_updatereqfwd = 30,
- dns_nsstatscounter_updaterespfwd = 31,
- dns_nsstatscounter_updatefwdfail = 32,
- dns_nsstatscounter_updatedone = 33,
- dns_nsstatscounter_updatefail = 34,
- dns_nsstatscounter_updatebadprereq = 35,
-
- dns_nsstatscounter_max = 36
+ dns_nsstatscounter_subnetclientin = 3,
+ dns_nsstatscounter_badednsver = 4,
+ dns_nsstatscounter_tsigin = 5,
+ dns_nsstatscounter_sig0in = 6,
+ dns_nsstatscounter_invalidsig = 7,
+ dns_nsstatscounter_tcp = 8,
+
+ dns_nsstatscounter_authrej = 9,
+ dns_nsstatscounter_recurserej = 10,
+ dns_nsstatscounter_xfrrej = 11,
+ dns_nsstatscounter_updaterej = 12,
+
+ dns_nsstatscounter_response = 13,
+ dns_nsstatscounter_truncatedresp = 14,
+ dns_nsstatscounter_edns0out = 15,
+ dns_nsstatscounter_tsigout = 16,
+ dns_nsstatscounter_sig0out = 17,
+
+ dns_nsstatscounter_success = 18,
+ dns_nsstatscounter_authans = 19,
+ dns_nsstatscounter_nonauthans = 20,
+ dns_nsstatscounter_referral = 21,
+ dns_nsstatscounter_nxrrset = 22,
+ dns_nsstatscounter_servfail = 23,
+ dns_nsstatscounter_formerr = 24,
+ dns_nsstatscounter_nxdomain = 25,
+ dns_nsstatscounter_recursion = 26,
+ dns_nsstatscounter_duplicate = 27,
+ dns_nsstatscounter_dropped = 28,
+ dns_nsstatscounter_failure = 29,
+
+ dns_nsstatscounter_xfrdone = 30,
+
+ dns_nsstatscounter_updatereqfwd = 31,
+ dns_nsstatscounter_updaterespfwd = 32,
+ dns_nsstatscounter_updatefwdfail = 33,
+ dns_nsstatscounter_updatedone = 34,
+ dns_nsstatscounter_updatefail = 35,
+ dns_nsstatscounter_updatebadprereq = 36,
+
+ dns_nsstatscounter_max = 37
};
void
diff --git a/bin/named/sortlist.c b/bin/named/sortlist.c
index 0710fb1..37af55c 100644
--- a/bin/named/sortlist.c
+++ b/bin/named/sortlist.c
@@ -72,7 +72,7 @@ ns_sortlist_setup(dns_acl_t *acl, isc_netaddr_t *clientaddr,
try_elt = e;
}
- if (dns_aclelement_match(clientaddr, NULL, try_elt,
+ if (dns_aclelement_match(clientaddr, NULL, NULL, NULL, try_elt,
&ns_g_server->aclenv,
&matched_elt)) {
if (order_elt != NULL) {
@@ -132,7 +132,7 @@ ns_sortlist_addrorder2(const isc_netaddr_t *addr, const void *arg) {
int
ns_sortlist_addrorder1(const isc_netaddr_t *addr, const void *arg) {
const dns_aclelement_t *matchelt = (const dns_aclelement_t *) arg;
- if (dns_aclelement_match(addr, NULL, matchelt,
+ if (dns_aclelement_match(addr, NULL, NULL, NULL, matchelt,
&ns_g_server->aclenv,
NULL)) {
return (0);
diff --git a/bin/named/statschannel.c b/bin/named/statschannel.c
index 1f72694..110dff4 100644
--- a/bin/named/statschannel.c
+++ b/bin/named/statschannel.c
@@ -152,6 +152,8 @@ init_desc(void) {
SET_NSSTATDESC(requestv4, "IPv4 requests received", "Requestv4");
SET_NSSTATDESC(requestv6, "IPv6 requests received", "Requestv6");
SET_NSSTATDESC(edns0in, "requests with EDNS(0) received", "ReqEdns0");
+ SET_NSSTATDESC(subnetclientin, "requests with EDNS(0) subnet client received",
+ "ReqEdns0SubnetClient");
SET_NSSTATDESC(badednsver,
"requests with unsupported EDNS version received",
"ReqBadEDNSVer");
diff --git a/lib/dns/acl.c b/lib/dns/acl.c
index 2f272e2..44ac41e 100644
--- a/lib/dns/acl.c
+++ b/lib/dns/acl.c
@@ -249,12 +249,14 @@ dns_acl_isnone(dns_acl_t *acl)
* element or radix entry, return with a negative value in match.
*/
isc_result_t
-dns_acl_match(const isc_netaddr_t *reqaddr,
- const dns_name_t *reqsigner,
- const dns_acl_t *acl,
- const dns_aclenv_t *env,
- int *match,
- const dns_aclelement_t **matchelt)
+dns_acl_match_with_client(const isc_netaddr_t *reqaddr,
+ const isc_netaddr_t *clientaddr,
+ isc_uint8_t *scope,
+ const dns_name_t *reqsigner,
+ const dns_acl_t *acl,
+ const dns_aclenv_t *env,
+ int *match,
+ const dns_aclelement_t **matchelt)
{
isc_uint16_t bitlen, family;
isc_prefix_t pfx;
@@ -307,7 +309,7 @@ dns_acl_match(const isc_netaddr_t *reqaddr,
return (ISC_R_SUCCESS);
}
- if (dns_aclelement_match(reqaddr, reqsigner,
+ if (dns_aclelement_match(reqaddr, clientaddr, scope, reqsigner,
e, env, matchelt)) {
if (match_num == -1 || e->node_num < match_num) {
if (e->negative == ISC_TRUE)
@@ -324,6 +326,18 @@ dns_acl_match(const isc_netaddr_t *reqaddr,
return (ISC_R_SUCCESS);
}
+isc_result_t
+dns_acl_match(const isc_netaddr_t *reqaddr,
+ const dns_name_t *reqsigner,
+ const dns_acl_t *acl,
+ const dns_aclenv_t *env,
+ int *match,
+ const dns_aclelement_t **matchelt)
+{
+ return dns_acl_match_with_client(reqaddr, NULL, NULL, reqsigner, acl,
+ env, match, matchelt);
+}
+
/*
* Merge the contents of one ACL into another. Call dns_iptable_merge()
* for the IP tables, then concatenate the element arrays.
@@ -433,6 +447,8 @@ dns_acl_merge(dns_acl_t *dest, dns_acl_t *source, isc_boolean_t pos)
*/
isc_boolean_t
dns_aclelement_match(const isc_netaddr_t *reqaddr,
+ const isc_netaddr_t *clientaddr,
+ isc_uint8_t *scope,
const dns_name_t *reqsigner,
const dns_aclelement_t *e,
const dns_aclenv_t *env,
@@ -442,6 +458,8 @@ dns_aclelement_match(const isc_netaddr_t *reqaddr,
int indirectmatch;
isc_result_t result;
#ifdef HAVE_GEOIP
+ const isc_netaddr_t *geoaddr = clientaddr?clientaddr:reqaddr;
+ GeoIPLookup gl;
uint32_t ipnum = 0;
#ifdef HAVE_GEOIP_V6
const geoipv6_t *ipnum6 = NULL;
@@ -455,18 +473,18 @@ dns_aclelement_match(const isc_netaddr_t *reqaddr,
#endif
#endif /* HAVE_GEOIP_V6 */
- switch ( reqaddr->family ) {
+ switch ( geoaddr->family ) {
case AF_INET:
- ipnum = ntohl(reqaddr->type.in.s_addr);
+ ipnum = ntohl(geoaddr->type.in.s_addr);
#ifdef DEBUG_GEOIP
- inet_ntop(AF_INET, &reqaddr->type.in, ipstr, INET_ADDRSTRLEN);
+ inet_ntop(AF_INET, &geoaddr->type.in, ipstr, INET_ADDRSTRLEN);
#endif
break;
#ifdef HAVE_GEOIP_V6
case AF_INET6:
- ipnum6 = &reqaddr->type.in6;
+ ipnum6 = &geoaddr->type.in6;
#ifdef DEBUG_GEOIP
- inet_ntop(AF_INET6, &reqaddr->type.in6, ipstr, INET6_ADDRSTRLEN);
+ inet_ntop(AF_INET6, &geoaddr->type.in6, ipstr, INET6_ADDRSTRLEN);
#endif
break;
#endif
@@ -521,10 +539,10 @@ dns_aclelement_match(const isc_netaddr_t *reqaddr,
switch ( e->geoip_countryDB.subtype ) {
case geoip_countryDB_country_code:
if ( ipnum )
- result = GeoIP_country_code_by_ipnum( ns_g_geoip_countryDB, ipnum );
+ result = GeoIP_country_code_by_ipnum_gl( ns_g_geoip_countryDB, ipnum, &gl );
#ifdef HAVE_GEOIP_V6
else if ( ipnum6 )
- result = GeoIP_country_code_by_ipnum_v6( ns_g_geoip_countryDB_v6, *ipnum6 );
+ result = GeoIP_country_code_by_ipnum_v6_gl( ns_g_geoip_countryDB_v6, *ipnum6, &gl );
#endif
if ( result )
georesult = ( strncasecmp( e->geoip_countryDB.country_code, result, 2 ) == 0 );
@@ -539,10 +557,10 @@ dns_aclelement_match(const isc_netaddr_t *reqaddr,
break;
case geoip_countryDB_country_code3:
if ( ipnum )
- result = GeoIP_country_code3_by_ipnum( ns_g_geoip_countryDB, ipnum );
+ result = GeoIP_country_code3_by_ipnum_gl( ns_g_geoip_countryDB, ipnum, &gl );
#ifdef HAVE_GEOIP_V6
else if ( ipnum6 )
- result = GeoIP_country_code3_by_ipnum_v6( ns_g_geoip_countryDB_v6, *ipnum6 );
+ result = GeoIP_country_code3_by_ipnum_v6_gl( ns_g_geoip_countryDB_v6, *ipnum6, &gl );
#endif
if ( result )
georesult = ( strncasecmp( e->geoip_countryDB.country_code3, result, 3 ) == 0 );
@@ -557,10 +575,10 @@ dns_aclelement_match(const isc_netaddr_t *reqaddr,
break;
case geoip_countryDB_country_name:
if ( ipnum )
- result = GeoIP_country_name_by_ipnum( ns_g_geoip_countryDB, ipnum );
+ result = GeoIP_country_name_by_ipnum_gl( ns_g_geoip_countryDB, ipnum, &gl );
#ifdef HAVE_GEOIP_V6
else if ( ipnum6 )
- result = GeoIP_country_name_by_ipnum_v6( ns_g_geoip_countryDB_v6, *ipnum6 );
+ result = GeoIP_country_name_by_ipnum_v6_gl( ns_g_geoip_countryDB_v6, *ipnum6, &gl );
#endif
if ( result )
georesult = ( strcasecmp( e->geoip_countryDB.country_name, result ) == 0 );
@@ -576,6 +594,8 @@ dns_aclelement_match(const isc_netaddr_t *reqaddr,
default:
break;
} /* switch */
+ if (georesult && scope && *scope == 0)
+ *scope = gl.netmask;
return( georesult ? ISC_TRUE : ISC_FALSE );
} /* case geoip_countryDB */
@@ -783,6 +803,8 @@ dns_aclelement_match(const isc_netaddr_t *reqaddr,
"client %s: geoip_cityDB found no record",
ipstr);
#endif
+ if (georesult && record && scope && *scope == 0)
+ *scope = record->netmask;
return( georesult ? ISC_TRUE : ISC_FALSE );
} /* case geoip_cityDB */
@@ -793,7 +815,7 @@ dns_aclelement_match(const isc_netaddr_t *reqaddr,
if ( !ipnum || !ns_g_geoip_regionDB )
return(ISC_FALSE);
- if (( record = GeoIP_region_by_ipnum( ns_g_geoip_regionDB, ipnum) )) {
+ if (( record = GeoIP_region_by_ipnum_gl( ns_g_geoip_regionDB, ipnum, &gl ) )) {
switch ( e->geoip_regionDB.subtype ) {
case geoip_regionDB_country_code:
if ( record->country_code )
@@ -830,6 +852,8 @@ dns_aclelement_match(const isc_netaddr_t *reqaddr,
"client %s: geoip_regionDB found no record",
ipstr);
#endif
+ if (georesult && scope && *scope == 0)
+ *scope = gl.netmask;
return( georesult ? ISC_TRUE : ISC_FALSE );
} /* case geoip_regionDB */
@@ -842,7 +866,7 @@ dns_aclelement_match(const isc_netaddr_t *reqaddr,
switch ( e->geoip_ispDB.subtype ) {
case geoip_ispDB_name:
- if (( result = GeoIP_name_by_ipnum( ns_g_geoip_ispDB, ipnum ) ))
+ if (( result = GeoIP_name_by_ipnum_gl( ns_g_geoip_ispDB, ipnum, &gl ) ))
georesult = ( strcasecmp( e->geoip_ispDB.name, result ) == 0 );
#ifdef DEBUG_GEOIP
isc_log_write(dns_lctx, DNS_LOGCATEGORY_NOTIFY,
@@ -856,6 +880,8 @@ dns_aclelement_match(const isc_netaddr_t *reqaddr,
default:
break;
} /* switch */
+ if (georesult && scope && *scope == 0)
+ *scope = gl.netmask;
return( georesult ? ISC_TRUE : ISC_FALSE );
} /* case geoip_ispDB */
@@ -868,7 +894,7 @@ dns_aclelement_match(const isc_netaddr_t *reqaddr,
switch ( e->geoip_orgDB.subtype ) {
case geoip_orgDB_name:
- if (( result = GeoIP_name_by_ipnum( ns_g_geoip_orgDB, ipnum ) ))
+ if (( result = GeoIP_name_by_ipnum_gl( ns_g_geoip_orgDB, ipnum, &gl ) ))
georesult = ( strcasecmp( e->geoip_orgDB.name, result ) == 0 );
#ifdef DEBUG_GEOIP
isc_log_write(dns_lctx, DNS_LOGCATEGORY_NOTIFY,
@@ -882,6 +908,8 @@ dns_aclelement_match(const isc_netaddr_t *reqaddr,
default:
break;
} /* switch */
+ if (georesult && scope && *scope == 0)
+ *scope = gl.netmask;
return( georesult ? ISC_TRUE : ISC_FALSE );
} /* case geoip_orgDB */
@@ -894,7 +922,7 @@ dns_aclelement_match(const isc_netaddr_t *reqaddr,
switch ( e->geoip_asDB.subtype ) {
case geoip_asDB_org:
- if (( result = GeoIP_org_by_ipnum( ns_g_geoip_asDB, ipnum ) ))
+ if (( result = GeoIP_name_by_ipnum_gl( ns_g_geoip_asDB, ipnum, &gl ) ))
georesult = ( strcasecmp( e->geoip_asDB.org, result ) == 0 );
#ifdef DEBUG_GEOIP
isc_log_write(dns_lctx, DNS_LOGCATEGORY_NOTIFY,
@@ -908,6 +936,8 @@ dns_aclelement_match(const isc_netaddr_t *reqaddr,
default:
break;
} /* switch */
+ if (georesult && scope && *scope == 0)
+ *scope = gl.netmask;
return( georesult ? ISC_TRUE : ISC_FALSE );
} /* case geoip_asDB */
@@ -920,7 +950,7 @@ dns_aclelement_match(const isc_netaddr_t *reqaddr,
switch ( e->geoip_netspeedDB.subtype ) {
case geoip_netspeedDB_id:
- result = GeoIP_id_by_ipnum( ns_g_geoip_netspeedDB, ipnum );
+ result = GeoIP_id_by_ipnum_gl( ns_g_geoip_netspeedDB, ipnum, &gl );
georesult = ( e->geoip_netspeedDB.id == result );
#ifdef DEBUG_GEOIP
isc_log_write(dns_lctx, DNS_LOGCATEGORY_NOTIFY,
@@ -934,6 +964,8 @@ dns_aclelement_match(const isc_netaddr_t *reqaddr,
default:
break;
} /* switch */
+ if (georesult && scope && *scope == 0)
+ *scope = gl.netmask;
return( georesult ? ISC_TRUE : ISC_FALSE );
} /* case geoip_netspeedDB */
@@ -946,7 +978,7 @@ dns_aclelement_match(const isc_netaddr_t *reqaddr,
switch ( e->geoip_domainDB.subtype ) {
case geoip_domainDB_name:
- if (( result = GeoIP_name_by_ipnum( ns_g_geoip_domainDB, ipnum ) ))
+ if (( result = GeoIP_name_by_ipnum_gl( ns_g_geoip_domainDB, ipnum, &gl ) ))
georesult = ( strcasecmp( e->geoip_domainDB.name, result ) == 0 );
#ifdef DEBUG_GEOIP
isc_log_write(dns_lctx, DNS_LOGCATEGORY_NOTIFY,
@@ -960,6 +992,8 @@ dns_aclelement_match(const isc_netaddr_t *reqaddr,
default:
break;
} /* switch */
+ if (georesult && scope && *scope == 0)
+ *scope = gl.netmask;
return( georesult ? ISC_TRUE : ISC_FALSE );
} /* case geoip_domainDB */
@@ -982,8 +1016,8 @@ dns_aclelement_match(const isc_netaddr_t *reqaddr,
INSIST(0);
}
- result = dns_acl_match(reqaddr, reqsigner, inner, env,
- &indirectmatch, matchelt);
+ result = dns_acl_match_with_client(reqaddr, clientaddr, scope, reqsigner, inner, env,
+ &indirectmatch, matchelt);
INSIST(result == ISC_R_SUCCESS);
/*
diff --git a/lib/dns/include/dns/acl.h b/lib/dns/include/dns/acl.h
index 26c6912..0d6423e 100644
--- a/lib/dns/include/dns/acl.h
+++ b/lib/dns/include/dns/acl.h
@@ -359,8 +359,26 @@ dns_acl_match(const isc_netaddr_t *reqaddr,
*\li #ISC_R_SUCCESS Always succeeds.
*/
+isc_result_t
+dns_acl_match_with_client(const isc_netaddr_t *reqaddr,
+ const isc_netaddr_t *clientaddr,
+ isc_uint8_t *scope,
+ const dns_name_t *reqsigner,
+ const dns_acl_t *acl,
+ const dns_aclenv_t *env,
+ int *match,
+ const dns_aclelement_t **matchelt);
+/*%<
+ * Similar to dns_acl_match but should be provided with the IP
+ * address of the client (through EDNS0 client subnet extension) in
+ * addition to the IP address of the requester. This IP address will be
+ * used to match GeoIP.
+ */
+
isc_boolean_t
dns_aclelement_match(const isc_netaddr_t *reqaddr,
+ const isc_netaddr_t *clientaddr,
+ isc_uint8_t *scope,
const dns_name_t *reqsigner,
const dns_aclelement_t *e,
const dns_aclenv_t *env,
--
1.8.4.rc3
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment