From b41c1aacbc550fa67bfa62df3114b1d668b9c8d8 Mon Sep 17 00:00:00 2001 From: Mark Andrews Date: Fri, 6 Oct 2017 13:01:14 +1100 Subject: [PATCH] 4759. [func] Add logging channel "trust-anchor-telementry" to record trust-anchor-telementry in incoming requests. Both _ta-XXXX./NULL and EDNS KEY-TAG options are logged. [RT #46124] --- CHANGES | 5 +++ bin/named/statschannel.c | 1 + bin/tests/system/dnssec/tests.sh | 16 ++++++-- doc/arm/logging-categories.xml | 10 +++++ lib/ns/client.c | 40 ++++++++++++++++++++ lib/ns/include/ns/client.h | 2 + lib/ns/include/ns/log.h | 1 + lib/ns/include/ns/stats.h | 3 +- lib/ns/log.c | 1 + lib/ns/query.c | 64 +++++++++++++++++++++++++++++++- 10 files changed, 137 insertions(+), 6 deletions(-) diff --git a/CHANGES b/CHANGES index f3c54c8fc1..ebc45adca9 100644 --- a/CHANGES +++ b/CHANGES @@ -1,3 +1,8 @@ +4759. [func] Add logging channel "trust-anchor-telementry" to + record trust-anchor-telementry in incoming requests. + Both _ta-XXXX./NULL and EDNS KEY-TAG options + are logged. [RT #46124] + 4758. [doc] Remove documentation of unimplemented "topology". [RT #46161] diff --git a/bin/named/statschannel.c b/bin/named/statschannel.c index 848d5e0e03..a8e18fd870 100644 --- a/bin/named/statschannel.c +++ b/bin/named/statschannel.c @@ -302,6 +302,7 @@ init_desc(void) { "successful uses of stale cache data after lookup failure", "QryUsedStale"); SET_NSSTATDESC(prefetch, "queries triggered prefetch", "Prefetch"); + SET_NSSTATDESC(keytagopt, "Keytag option received", "KeyTagOpt"); INSIST(i == ns_statscounter_max); /* Initialize resolver statistics */ diff --git a/bin/tests/system/dnssec/tests.sh b/bin/tests/system/dnssec/tests.sh index e02b44cf45..8e968db64b 100644 --- a/bin/tests/system/dnssec/tests.sh +++ b/bin/tests/system/dnssec/tests.sh @@ -3315,16 +3315,24 @@ n=`expr $n + 1` if [ $ret != 0 ]; then echo "I:failed"; fi status=`expr $status + $ret` -echo "I:check that trust-anchor-telemetry queries are received ($n)" +echo "I:check that _ta-XXXX trust-anchor-telemetry queries are logged ($n)" ret=0 -grep "query '_ta-[0-9a-f]*/NULL/IN' approved" ns1/named.run > /dev/null || ret=1 +grep "trust-anchor-telemetry '_ta-[0-9a-f]*/IN' from" ns1/named.run > /dev/null || ret=1 n=`expr $n + 1` if [ $ret != 0 ]; then echo "I:failed"; fi status=`expr $status + $ret` -echo "I:check that trust-anchor-telemetry are not sent when disabled ($n)" +echo "I:check that _ta-AAAA trust-anchor-telemetry are not sent when disabled ($n)" ret=0 -grep "sending trust-anchor-telemetry query '_ta-[0-9a-f]*/NULL" ns1/named.run > /dev/null && ret=1 +grep "sending trust-anchor-telemetry query '_ta-[0-9a-f]*/IN" ns1/named.run > /dev/null && ret=1 +n=`expr $n + 1` +if [ $ret != 0 ]; then echo "I:failed"; fi +status=`expr $status + $ret` + +echo "I:check that KEY-TAG trust-anchor-telemetry queries are logged ($n)" +ret=0 +$DIG $DIGOPTS . dnskey +ednsopt=KEY-TAG:ffff @10.53.0.1 > dig.out.ns4.test$n || ret=1 +grep "trust-anchor-telemetry './IN' from .* 65535" ns1/named.run > /dev/null || ret=1 n=`expr $n + 1` if [ $ret != 0 ]; then echo "I:failed"; fi status=`expr $status + $ret` diff --git a/doc/arm/logging-categories.xml b/doc/arm/logging-categories.xml index 36232edcd5..62e1ed8265 100644 --- a/doc/arm/logging-categories.xml +++ b/doc/arm/logging-categories.xml @@ -324,6 +324,16 @@ + + + trust-anchor-telemetry + + + + Logs trust-anchor-telemetry requests received by named. + + + unmatched diff --git a/lib/ns/client.c b/lib/ns/client.c index d914b595ae..7a67ed1a6b 100644 --- a/lib/ns/client.c +++ b/lib/ns/client.c @@ -544,6 +544,12 @@ exit_check(ns_client_t *client) { client->mortal = ISC_FALSE; client->sendcb = NULL; + if (client->keytag != NULL) { + isc_mem_put(client->mctx, client->keytag, + client->keytag_len); + client->keytag_len = 0; + } + /* * Put the client on the inactive list. If we are aiming for * the "freed" state, it will be removed from the inactive @@ -612,6 +618,11 @@ exit_check(ns_client_t *client) { dns_message_puttemprdataset(client->message, &client->opt); } + if (client->keytag != NULL) { + isc_mem_put(client->mctx, client->keytag, + client->keytag_len); + client->keytag_len = 0; + } dns_message_destroy(&client->message); @@ -2094,6 +2105,23 @@ process_ecs(ns_client_t *client, isc_buffer_t *buf, size_t optlen) { return (ISC_R_SUCCESS); } +static isc_result_t +process_keytag(ns_client_t *client, isc_buffer_t *buf, size_t optlen) { + + if (optlen == 0 || (optlen % 2) != 0) { + isc_buffer_forward(buf, (unsigned int)optlen); + return (DNS_R_OPTERR); + } + + client->keytag = isc_mem_get(client->mctx, optlen); + if (client->keytag != NULL) { + client->keytag_len = optlen; + memmove(client->keytag, isc_buffer_current(buf), optlen); + } + isc_buffer_forward(buf, (unsigned int)optlen); + return (ISC_R_SUCCESS); +} + static isc_result_t process_opt(ns_client_t *client, dns_rdataset_t *opt) { dns_rdata_t rdata; @@ -2190,6 +2218,16 @@ process_opt(ns_client_t *client, dns_rdataset_t *opt) { ns_statscounter_padopt); isc_buffer_forward(&optbuf, optlen); break; + case DNS_OPT_KEY_TAG: + result = process_keytag(client, &optbuf, + optlen); + if (result != ISC_R_SUCCESS) { + ns_client_error(client, result); + return (result); + } + ns_stats_increment(client->sctx->nsstats, + ns_statscounter_keytagopt); + break; default: ns_stats_increment(client->sctx->nsstats, ns_statscounter_otheropt); @@ -3014,6 +3052,8 @@ client_create(ns_clientmgr_t *manager, ns_client_t **clientp) { ISC_LINK_INIT(client, link); ISC_LINK_INIT(client, rlink); ISC_QLINK_INIT(client, ilink); + client->keytag = NULL; + client->keytag_len = 0; /* * We call the init routines for the various kinds of client here, diff --git a/lib/ns/include/ns/client.h b/lib/ns/include/ns/client.h index 4b9ccf424d..e5ec70dacf 100644 --- a/lib/ns/include/ns/client.h +++ b/lib/ns/include/ns/client.h @@ -164,6 +164,8 @@ struct ns_client { ISC_QLINK(ns_client_t) ilink; unsigned char cookie[8]; isc_uint32_t expire; + unsigned char *keytag; + isc_uint16_t keytag_len; }; typedef ISC_QUEUE(ns_client_t) client_queue_t; diff --git a/lib/ns/include/ns/log.h b/lib/ns/include/ns/log.h index 0355e84e68..d6997eb3e6 100644 --- a/lib/ns/include/ns/log.h +++ b/lib/ns/include/ns/log.h @@ -24,6 +24,7 @@ LIBNS_EXTERNAL_DATA extern isc_logmodule_t ns_modules[]; #define NS_LOGCATEGORY_QUERIES (&ns_categories[3]) #define NS_LOGCATEGORY_UPDATE_SECURITY (&ns_categories[4]) #define NS_LOGCATEGORY_QUERY_ERRORS (&ns_categories[5]) +#define NS_LOGCATEGORY_TAT (&ns_categories[6]) /* * Backwards compatibility. diff --git a/lib/ns/include/ns/stats.h b/lib/ns/include/ns/stats.h index cb734f4524..61e68a1977 100644 --- a/lib/ns/include/ns/stats.h +++ b/lib/ns/include/ns/stats.h @@ -97,8 +97,9 @@ enum { ns_statscounter_usedstale = 62, ns_statscounter_prefetch = 63, + ns_statscounter_keytagopt = 64, - ns_statscounter_max = 64 + ns_statscounter_max = 65 }; void diff --git a/lib/ns/log.c b/lib/ns/log.c index 82860780f9..741146976a 100644 --- a/lib/ns/log.c +++ b/lib/ns/log.c @@ -31,6 +31,7 @@ LIBNS_EXTERNAL_DATA isc_logcategory_t ns_categories[] = { { "unmatched", 0 }, { "update-security", 0 }, { "query-errors", 0 }, + { "trust-anchor-telemetry", 0 }, { NULL, 0 } }; diff --git a/lib/ns/query.c b/lib/ns/query.c index cf9b78e218..ee156efe6a 100644 --- a/lib/ns/query.c +++ b/lib/ns/query.c @@ -4027,7 +4027,7 @@ rpz_rewrite(ns_client_t *client, dns_rdatatype_t qtype, zbits &= allowed; if (zbits != 0) { isc_netaddr_fromsockaddr(&netaddr, - &client->peeraddr); + &client->peeraddr); result = rpz_rewrite_ip(client, &netaddr, qtype, DNS_RPZ_TYPE_CLIENT_IP, zbits, &rdataset); @@ -10478,6 +10478,66 @@ query_done(query_ctx_t *qctx) { return (qctx->result); } +static inline void +log_tat(ns_client_t *client) { + char namebuf[DNS_NAME_FORMATSIZE]; + char clientbuf[ISC_NETADDR_FORMATSIZE]; + char classname[DNS_RDATACLASS_FORMATSIZE]; + isc_netaddr_t netaddr; + char *tags = NULL; + size_t taglen = 0; + + if (!isc_log_wouldlog(ns_lctx, ISC_LOG_INFO)) { + return; + } + + if ((client->query.qtype != dns_rdatatype_null || + !dns_name_istat(client->query.qname)) && + (client->keytag == NULL || + client->query.qtype != dns_rdatatype_dnskey)) + { + return; + } + + isc_netaddr_fromsockaddr(&netaddr, &client->peeraddr); + dns_name_format(client->query.qname, namebuf, sizeof(namebuf)); + isc_netaddr_format(&client->destaddr, clientbuf, sizeof(clientbuf)); + dns_rdataclass_format(client->view->rdclass, classname, + sizeof(classname)); + + if (client->query.qtype == dns_rdatatype_dnskey) { + isc_uint16_t keytags = client->keytag_len / 2; + size_t len = taglen = sizeof("65000") * keytags + 1; + char *cp = tags = isc_mem_get(client->mctx, taglen); + int i = 0; + + INSIST(client->keytag != NULL); + if (tags != NULL) { + while (keytags-- > 0U) { + int n; + isc_uint16_t keytag; + keytag = (client->keytag[i * 2] << 8) | + client->keytag[i * 2 + 1]; + n = snprintf(cp, len, " %u", keytag); + if (n > 0 && (size_t)n <= len) { + cp += n; + len -= n; + i++; + } else { + break; + } + } + } + } + + isc_log_write(ns_lctx, NS_LOGCATEGORY_TAT, NS_LOGMODULE_QUERY, + ISC_LOG_INFO, "trust-anchor-telemetry '%s/%s' from %s%s", + namebuf, classname, clientbuf, tags != NULL? tags : ""); + if (tags != NULL) { + isc_mem_put(client->mctx, tags, taglen); + } +} + static inline void log_query(ns_client_t *client, unsigned int flags, unsigned int extflags) { char namebuf[DNS_NAME_FORMATSIZE]; @@ -10691,6 +10751,8 @@ ns_query_start(ns_client_t *client) { client->query.qtype = qtype = rdataset->type; dns_rdatatypestats_increment(client->sctx->rcvquerystats, qtype); + log_tat(client); + if (dns_rdatatype_ismeta(qtype)) { switch (qtype) { case dns_rdatatype_any: