allow dns_clientinfo to store client ECS data

this brings DNS_CLIENTINFO_VERSION into line with the subscription
branch so that fixes applied to clientinfo processing can also be
applied to the main branch without diverging.

(cherry picked from commit 737e658602)
This commit is contained in:
Evan Hunt 2021-11-02 22:38:45 -07:00
parent f9926228e1
commit 317ef804c0
6 changed files with 136 additions and 39 deletions

View file

@ -14,6 +14,7 @@
/*! \file */
#include <dns/clientinfo.h>
#include <dns/ecs.h>
void
dns_clientinfomethods_init(dns_clientinfomethods_t *methods,
@ -24,8 +25,14 @@ dns_clientinfomethods_init(dns_clientinfomethods_t *methods,
}
void
dns_clientinfo_init(dns_clientinfo_t *ci, void *data, void *versionp) {
dns_clientinfo_init(dns_clientinfo_t *ci, void *data, dns_ecs_t *ecs,
void *versionp) {
ci->version = DNS_CLIENTINFO_VERSION;
ci->data = data;
ci->dbversion = versionp;
if (ecs != NULL) {
ci->ecs = *ecs;
} else {
dns_ecs_init(&ci->ecs);
}
}

View file

@ -15,36 +15,99 @@
#include <string.h>
#include <isc/buffer.h>
#include <isc/mem.h>
#include <isc/netaddr.h>
#include <isc/print.h>
#include <isc/util.h>
#include <dns/ecs.h>
#include <dns/nsec.h>
#include <dns/rbt.h>
#include <dns/rdata.h>
#include <dns/rdatatype.h>
#include <dns/result.h>
#include <dns/types.h>
void
dns_ecs_init(dns_ecs_t *ecs) {
isc_netaddr_unspec(&ecs->addr);
ecs->source = 0;
ecs->scope = 0xff;
}
bool
dns_ecs_equals(const dns_ecs_t *ecs1, const dns_ecs_t *ecs2) {
const unsigned char *addr1, *addr2;
uint8_t mask;
size_t alen;
REQUIRE(ecs1 != NULL && ecs2 != NULL);
if (ecs1->source != ecs2->source ||
ecs1->addr.family != ecs2->addr.family) {
return (false);
}
alen = (ecs1->source + 7) / 8;
if (alen == 0) {
return (true);
}
switch (ecs1->addr.family) {
case AF_INET:
INSIST(alen <= 4);
addr1 = (const unsigned char *)&ecs1->addr.type.in;
addr2 = (const unsigned char *)&ecs2->addr.type.in;
break;
case AF_INET6:
INSIST(alen <= 16);
addr1 = (const unsigned char *)&ecs1->addr.type.in6;
addr2 = (const unsigned char *)&ecs2->addr.type.in6;
break;
default:
INSIST(0);
ISC_UNREACHABLE();
}
/*
* XXXMUKS: Fix me when resolver ECS gets merged where scope
* gets initialized to 0xff.
* Compare all octets except the final octet of the address
* prefix.
*/
ecs->scope = 0;
if (alen > 1 && memcmp(addr1, addr2, alen - 1) != 0) {
return (false);
}
/*
* It should not be necessary to mask the final octet; all
* bits past the source prefix length are supposed to be 0.
* However, it seems prudent not to omit them from the
* comparison anyway.
*/
mask = (~0U << (8 - (ecs1->source % 8))) & 0xff;
if (mask == 0) {
mask = 0xff;
}
if ((addr1[alen - 1] & mask) != (addr2[alen - 1] & mask)) {
return (false);
}
return (true);
}
void
dns_ecs_format(dns_ecs_t *ecs, char *buf, size_t size) {
dns_ecs_format(const dns_ecs_t *ecs, char *buf, size_t size) {
size_t len;
char *p;
REQUIRE(ecs != NULL);
REQUIRE(buf != NULL);
REQUIRE(size >= DNS_ECS_FORMATSIZE);
isc_netaddr_format(&ecs->addr, buf, (unsigned int)size);
isc_netaddr_format(&ecs->addr, buf, size);
len = strlen(buf);
INSIST(size >= len);
buf += len;
size -= len;
snprintf(buf, size, "/%u/%u", ecs->source, ecs->scope);
p = buf + len;
snprintf(p, size - len, "/%d/%d", ecs->source,
ecs->scope == 0xff ? 0 : ecs->scope);
}

View file

@ -42,17 +42,20 @@
#include <isc/sockaddr.h>
#include <isc/types.h>
#include <dns/ecs.h>
ISC_LANG_BEGINDECLS
/*****
***** Types
*****/
#define DNS_CLIENTINFO_VERSION 2
#define DNS_CLIENTINFO_VERSION 3
typedef struct dns_clientinfo {
uint16_t version;
void *data;
void *dbversion;
uint16_t version;
void *data;
void *dbversion;
dns_ecs_t ecs;
} dns_clientinfo_t;
typedef isc_result_t (*dns_clientinfo_sourceip_t)(dns_clientinfo_t *client,
@ -75,6 +78,7 @@ dns_clientinfomethods_init(dns_clientinfomethods_t *methods,
dns_clientinfo_sourceip_t sourceip);
void
dns_clientinfo_init(dns_clientinfo_t *ci, void *data, void *versionp);
dns_clientinfo_init(dns_clientinfo_t *ci, void *data, dns_ecs_t *ecs,
void *versionp);
ISC_LANG_ENDDECLS

View file

@ -19,17 +19,28 @@
#include <isc/netaddr.h>
#include <isc/types.h>
#include <dns/rdatatype.h>
#include <dns/types.h>
/*%
* Maximum scope values for IPv4 and IPv6.
*/
#ifndef ECS_MAX_V4_SCOPE
#define ECS_MAX_V4_SCOPE 24
#endif
#ifndef ECS_MAX_V6_SCOPE
#define ECS_MAX_V6_SCOPE 56
#endif
struct dns_ecs {
isc_netaddr_t addr;
uint8_t source;
uint8_t scope;
};
#define DNS_ECS_FORMATSIZE \
(ISC_NETADDR_FORMATSIZE + 8) /* <address>/NNN/NNN \
*/
/* <address>/NNN/NNN */
#define DNS_ECS_FORMATSIZE (ISC_NETADDR_FORMATSIZE + 9)
ISC_LANG_BEGINDECLS
@ -42,8 +53,19 @@ dns_ecs_init(dns_ecs_t *ecs);
* \li 'ecs' is not NULL and points to a valid dns_ecs structure.
*/
bool
dns_ecs_equals(const dns_ecs_t *ecs1, const dns_ecs_t *ecs2);
/*%<
* Determine whether two ECS address prefixes are equal (except the
* scope prefix-length field).
*
* 'ecs1->source' must exactly match 'ecs2->source'; the address families
* must match; and the first 'ecs1->source' bits of the addresses must
* match. Subsequent address bits and the 'scope' values are ignored.
*/
void
dns_ecs_format(dns_ecs_t *ecs, char *buf, size_t size);
dns_ecs_format(const dns_ecs_t *ecs, char *buf, size_t size);
/*%<
* Format an ECS record as text. Result is guaranteed to be null-terminated.
*
@ -52,5 +74,4 @@ dns_ecs_format(dns_ecs_t *ecs, char *buf, size_t size);
* \li 'buf' is not NULL.
* \li 'size' is at least DNS_ECS_FORMATSIZE
*/
ISC_LANG_ENDDECLS

View file

@ -1389,7 +1389,7 @@ query_getdb(ns_client_t *client, dns_name_t *name, dns_rdatatype_t qtype,
dns_db_t *tdbp;
dns_clientinfomethods_init(&cm, ns_client_sourceip);
dns_clientinfo_init(&ci, client, NULL);
dns_clientinfo_init(&ci, client, &client->ecs, NULL);
tdbp = NULL;
tresult = dns_view_searchdlz(client->view, name, zonelabels,
@ -1530,7 +1530,7 @@ query_additionalauthfind(dns_db_t *db, dns_dbversion_t *version,
isc_result_t result;
dns_clientinfomethods_init(&cm, ns_client_sourceip);
dns_clientinfo_init(&ci, client, NULL);
dns_clientinfo_init(&ci, client, NULL, NULL);
/*
* Since we are looking for authoritative data, we do not set
@ -1693,7 +1693,7 @@ query_additional_cb(void *arg, const dns_name_t *name, dns_rdatatype_t qtype,
CTRACE(ISC_LOG_DEBUG(3), "query_additional_cb");
dns_clientinfomethods_init(&cm, ns_client_sourceip);
dns_clientinfo_init(&ci, client, NULL);
dns_clientinfo_init(&ci, client, NULL, NULL);
/*
* We treat type A additional section processing as if it
@ -2285,7 +2285,7 @@ mark_secure(ns_client_t *client, dns_db_t *db, dns_name_t *name,
rdataset->trust = dns_trust_secure;
sigrdataset->trust = dns_trust_secure;
dns_clientinfomethods_init(&cm, ns_client_sourceip);
dns_clientinfo_init(&ci, client, NULL);
dns_clientinfo_init(&ci, client, NULL, NULL);
/*
* Save the updated secure state. Ignore failures.
@ -2322,7 +2322,7 @@ get_key(ns_client_t *client, dns_db_t *db, dns_rdata_rrsig_t *rrsig,
dns_clientinfo_t ci;
dns_clientinfomethods_init(&cm, ns_client_sourceip);
dns_clientinfo_init(&ci, client, NULL);
dns_clientinfo_init(&ci, client, NULL, NULL);
if (!dns_rdataset_isassociated(keyrdataset)) {
result = dns_db_findnodeext(db, &rrsig->signer, false, &cm, &ci,
@ -2876,7 +2876,7 @@ rpz_rrset_find(ns_client_t *client, dns_name_t *name, dns_rdatatype_t type,
node = NULL;
found = dns_fixedname_initname(&fixed);
dns_clientinfomethods_init(&cm, ns_client_sourceip);
dns_clientinfo_init(&ci, client, NULL);
dns_clientinfo_init(&ci, client, NULL, NULL);
result = dns_db_findext(*dbp, name, version, type, DNS_DBFIND_GLUEOK,
client->now, &node, found, &cm, &ci, *rdatasetp,
NULL);
@ -3025,7 +3025,7 @@ rpz_find_p(ns_client_t *client, dns_name_t *self_name, dns_rdatatype_t qtype,
CTRACE(ISC_LOG_DEBUG(3), "rpz_find_p");
dns_clientinfomethods_init(&cm, ns_client_sourceip);
dns_clientinfo_init(&ci, client, NULL);
dns_clientinfo_init(&ci, client, NULL, NULL);
/*
* Try to find either a CNAME or the type of record demanded by the
@ -4628,7 +4628,7 @@ query_findclosestnsec3(dns_name_t *qname, dns_db_t *db,
dns_name_clone(qname, &name);
labels = dns_name_countlabels(&name);
dns_clientinfomethods_init(&cm, ns_client_sourceip);
dns_clientinfo_init(&ci, client, NULL);
dns_clientinfo_init(&ci, client, NULL, NULL);
/*
* Map unknown algorithm to known value.
@ -4828,7 +4828,7 @@ redirect(ns_client_t *client, dns_name_t *name, dns_rdataset_t *rdataset,
dns_rdataset_init(&trdataset);
dns_clientinfomethods_init(&cm, ns_client_sourceip);
dns_clientinfo_init(&ci, client, NULL);
dns_clientinfo_init(&ci, client, &client->ecs, NULL);
if (WANTDNSSEC(client) && dns_db_iszone(*dbp) && dns_db_issecure(*dbp))
{
@ -4966,7 +4966,7 @@ redirect2(ns_client_t *client, dns_name_t *name, dns_rdataset_t *rdataset,
dns_rdataset_init(&trdataset);
dns_clientinfomethods_init(&cm, ns_client_sourceip);
dns_clientinfo_init(&ci, client, NULL);
dns_clientinfo_init(&ci, client, &client->ecs, NULL);
if (WANTDNSSEC(client) && dns_db_iszone(*dbp) && dns_db_issecure(*dbp))
{
@ -5787,7 +5787,9 @@ query_lookup(query_ctx_t *qctx) {
CALL_HOOK(NS_QUERY_LOOKUP_BEGIN, qctx);
dns_clientinfomethods_init(&cm, ns_client_sourceip);
dns_clientinfo_init(&ci, qctx->client, NULL);
dns_clientinfo_init(&ci, qctx->client,
HAVEECS(qctx->client) ? &qctx->client->ecs : NULL,
NULL);
/*
* We'll need some resources...
@ -8596,7 +8598,7 @@ query_notfound(query_ctx_t *qctx) {
dns_clientinfo_t ci;
dns_clientinfomethods_init(&cm, ns_client_sourceip);
dns_clientinfo_init(&ci, qctx->client, NULL);
dns_clientinfo_init(&ci, qctx->client, NULL, NULL);
dns_db_attach(qctx->view->hints, &qctx->db);
result = dns_db_findext(qctx->db, dns_rootname, NULL,
@ -10065,7 +10067,7 @@ query_coveringnsec(query_ctx_t *qctx) {
nowild = dns_fixedname_initname(&fnowild);
dns_clientinfomethods_init(&cm, ns_client_sourceip);
dns_clientinfo_init(&ci, qctx->client, NULL);
dns_clientinfo_init(&ci, qctx->client, NULL, NULL);
/*
* All signer names must be the same to accept.
@ -10788,7 +10790,7 @@ query_addsoa(query_ctx_t *qctx, unsigned int override_ttl,
node = NULL;
dns_clientinfomethods_init(&cm, ns_client_sourceip);
dns_clientinfo_init(&ci, client, NULL);
dns_clientinfo_init(&ci, client, NULL, NULL);
/*
* Don't add the SOA record for test which set "-T nosoa".
@ -10937,7 +10939,7 @@ query_addns(query_ctx_t *qctx) {
fname = dns_fixedname_initname(&foundname);
dns_clientinfomethods_init(&cm, ns_client_sourceip);
dns_clientinfo_init(&ci, client, NULL);
dns_clientinfo_init(&ci, client, NULL, NULL);
/*
* Get resources and make 'name' be the database origin.
@ -11039,7 +11041,7 @@ query_addbestns(query_ctx_t *qctx) {
CTRACE(ISC_LOG_DEBUG(3), "query_addbestns");
dns_clientinfomethods_init(&cm, ns_client_sourceip);
dns_clientinfo_init(&ci, client, NULL);
dns_clientinfo_init(&ci, client, NULL, NULL);
/*
* Find the right database.
@ -11244,7 +11246,7 @@ query_addwildcardproof(query_ctx_t *qctx, bool ispositive, bool nodata) {
CTRACE(ISC_LOG_DEBUG(3), "query_addwildcardproof");
dns_clientinfomethods_init(&cm, ns_client_sourceip);
dns_clientinfo_init(&ci, client, NULL);
dns_clientinfo_init(&ci, client, NULL, NULL);
/*
* If a name has been specifically flagged as needing

View file

@ -594,7 +594,7 @@ foreach_rrset(dns_db_t *db, dns_dbversion_t *ver, dns_name_t *name,
* different from the current version
*/
dns_db_currentversion(db, &oldver);
dns_clientinfo_init(&ci, NULL, (ver != oldver) ? ver : NULL);
dns_clientinfo_init(&ci, NULL, NULL, (ver != oldver) ? ver : NULL);
dns_db_closeversion(db, &oldver, false);
node = NULL;
@ -685,7 +685,7 @@ foreach_rr(dns_db_t *db, dns_dbversion_t *ver, dns_name_t *name,
* different from the current version
*/
dns_db_currentversion(db, &oldver);
dns_clientinfo_init(&ci, NULL, (ver != oldver) ? ver : NULL);
dns_clientinfo_init(&ci, NULL, NULL, (ver != oldver) ? ver : NULL);
dns_db_closeversion(db, &oldver, false);
if (type == dns_rdatatype_any) {