]> git.ipfire.org Git - thirdparty/bind9.git/commitdiff
allow dns_clientinfo to store client ECS data
authorEvan Hunt <each@isc.org>
Wed, 3 Nov 2021 05:38:45 +0000 (22:38 -0700)
committerEvan Hunt <each@isc.org>
Thu, 27 Jan 2022 21:53:59 +0000 (13:53 -0800)
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.

lib/dns/clientinfo.c
lib/dns/ecs.c
lib/dns/include/dns/clientinfo.h
lib/dns/include/dns/ecs.h
lib/ns/query.c
lib/ns/update.c

index 372aab10615e1430ff82b62544790aa0e5d48cc0..fe81d591c6822a91a8214c2a4be42b385ce681fa 100644 (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);
+       }
 }
index 2171a89dd52e671774c38e241ce96992edaf622b..ae88c4713e1e7b675ffe29b73da50ad59347fe0c 100644 (file)
 
 #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();
+       }
+
+       /*
+        * Compare all octets except the final octet of the address
+        * prefix.
+        */
+       if (alen > 1 && memcmp(addr1, addr2, alen - 1) != 0) {
+               return (false);
+       }
+
        /*
-        * XXXMUKS: Fix me when resolver ECS gets merged where scope
-        * gets initialized to 0xff.
+        * 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.
         */
-       ecs->scope = 0;
+       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);
 }
index 03891c7f600eed4ae627bb8373fbcb44d3df1cae..11965038384397e9d6c099805ed5aeffa48586d6 100644 (file)
 #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
index 2644a1ac749f6f48acf69177eed80903b725192a..d4cfe65233b5865942625b28793495cf98ae3814 100644 (file)
 #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
index 8fbbc09926d2619732c28b0a0b1547bb079234ae..d87d1f8ec96ae07e1138dbbccd26bb7e92698958 100644 (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
index b3b53e507a807c8a56bda3d9cbd6539bf7af48f4..47f9fcafeb3b3e05ba1e71dec391c43415043bf2 100644 (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) {