A Prometheus exporter that captures information from the BIND queries log file. It is based on the node_exporter and cf_exporter projects.
By default, this exporter's Stats collector doesn't do anything special that you can't get with the much better bind_exporter query stats. However, enabling the Names
collector with --filter.collectors="Names"
makes DNS query hits per name available (see the warning in the Names collector documentation below). This can be useful for a few use cases:
- Using the
--names.include.file
to see if a list of DNS names you would like to decommission are still receiving queries - Using the
--names.include.file
to identify if clients on your network are reaching out to forbidden domain names - Using the
--names.exclude.file
to see if your authoritative DNS server is receiving queries for domain names you don't own
Depending on the use case, enabling --names.capture-client
and --reverse-lookup
may be helpful.
Note that BIND does not log queries by default, so logging must be turned on before this collector will do much. On Debian-based systems, placing the following contents in /etc/bind/named.conf.logging
will enable logging:
logging {
channel syslog { syslog daemon; severity info; };
channel stdout { stderr; severity info; };
channel transfer_log {
file "/var/log/bind/bind.log" versions 10 size 50M;
severity info;
print-category yes;
print-severity yes;
print-time yes;
};
channel query_log {
file "/var/log/bind/queries.log" versions 10 size 50M;
severity debug;
print-category yes;
print-severity yes;
print-time yes;
};
category default { syslog; stdout; };
category update { syslog; };
category update-security { syslog; };
category security { syslog; };
category queries { query_log; };
category xfer-in { transfer_log; };
category xfer-out { transfer_log; };
category lame-servers { null; };
};
It is strongly suggested to enable rotation of the log file. On Debian-based systems, you can do this by creating the file /etc/logrotate.d/bind
with these contents:
/var/log/bind/bind.log {
daily
missingok
rotate 7
compress
delaycompress
notifempty
create 644 bind bind
}
/var/log/bind/queries.log {
daily
missingok
rotate 7
compress
delaycompress
notifempty
create 644 bind bind
postrotate
/usr/sbin/invoke-rc.d bind9 reload > /dev/null
endscript
}
Download the already existing binaries for your platform:
$ ./bind_query_exporter <flags>
Using the standard go install
(you must have Go already installed in your local machine):
$ go install github.com/DRuggeri/bind_query_exporter
$ bind_query_exporter <flags>
An official scratch-based Docker image is built with every tag and pushed to DockerHub and ghcr. Additionally, PRs will be tested by GitHubs actions.
The following images are available for use:
usage: bind_query_exporter [<flags>]
Flags:
-h, --help Show context-sensitive help (also try --help-long and --help-man).
--log="/var/log/bind/queries.log"
Path of the BIND query log to watch. Defaults to '/var/log/bind/queries.log' ($BIND_QUERY_EXPORTER_LOG)
--pattern="client(?: @0x[0-9a-f]+)? ([^\\s#]+).*query: ([^\\s]+).*IN ([^\\s]+)"
The regular expression pattern with three capturing matches for the client IP, the queried name, and the query type ($BIND_QUERY_EXPORTER_PATTERN)
--names.include.file="" Path to a file of DNS names that this exporter WILL export when the Names filter is enabled. One DNS name per line will be read. ($BIND_QUERY_EXPORTER_NAMES_INCLUDE_FILE)
--names.exclude.file="" Path to a file of DNS names that this exporter WILL NOT export when the Names filter is enabled. One DNS name per line will be read.
($BIND_QUERY_EXPORTER_NAMES_EXCLUDE_FILE)
--names.exclude-clients.file=""
Path to a file of reverse names or IP addresses that this exporter will ignore. One entry per line will be read. ($BIND_QUERY_EXPORTER_NAMES_EXCLUDE_CLIENTS_FILE)
--names.include-clients.file=""
Path to a file of reverse names or IP addresses that this exporter will capture. All others will be ignored. One entry per line will be read.
($BIND_QUERY_EXPORTER_NAMES_INCLUDE_CLIENTS_FILE)
--names.capture-client Enable capturing the client making the client IP or name as part of the vector. WARNING: This will can lead to lots of metrics in your Prometheus database!
($BIND_QUERY_EXPORTER_NAMES_CAPTURE_CLIENT)
--names.reverse-lookup When capture-client is enabled for the Names collector, perform a reverse DNS lookup to identify the client in the vector instead of the IP.
($BIND_QUERY_EXPORTER_NAMES_REVERSE_LOOKUP)
--stats.capture-client Enable capturing the client making the client IP or name as part of the vector. WARNING: This will can lead to lots of metrics in your Prometheus database!
($BIND_QUERY_EXPORTER_STATS_CAPTURE_CLIENT)
--stats.reverse-lookup When capture-client is enabled for the Stats collector, perform a reverse DNS lookup to identify the client in the vector instead of the IP. WARNING: this will create
queries to your DNS server which will probably be seen by this exporter... triggering an infinite loop of lookups if you do not have a DNS cache configured!!!!
($BIND_QUERY_EXPORTER_STATS_REVERSE_LOOKUP)
--filter.collectors="Stats"
Comma separated collectors to enable (Stats,Names) ($BIND_QUERY_EXPORTER_FILTER_COLLECTORS)
--metrics.namespace="bind_query"
Metrics Namespace ($BIND_QUERY_EXPORTER_METRICS_NAMESPACE)
--web.listen-address=":9197"
Address to listen on for web interface and telemetry ($BIND_QUERY_EXPORTER_WEB_LISTEN_ADDRESS)
--web.telemetry-path="/metrics"
Path under which to expose Prometheus metrics ($BIND_QUERY_EXPORTER_WEB_TELEMETRY_PATH)
--web.auth.username=WEB.AUTH.USERNAME
Username for web interface basic auth. Password is set via $BIND_QUERY_EXPORTER_WEB_AUTH_PASSWORD env variable ($BIND_QUERY_EXPORTER_WEB_AUTH_USERNAME)
--web.tls.cert_file=WEB.TLS.CERT_FILE
Path to a file that contains the TLS certificate (PEM format). If the certificate is signed by a certificate authority, the file should be the concatenation of the
server's certificate, any intermediates, and the CA's certificate ($BIND_QUERY_EXPORTER_WEB_TLS_CERTFILE)
--web.tls.key_file=WEB.TLS.KEY_FILE
Path to a file that contains the TLS private key (PEM format) ($BIND_QUERY_EXPORTER_WEB_TLS_KEYFILE)
--printMetrics Print the metrics this exporter exposes and exits. Default: false ($BIND_QUERY_EXPORTER_PRINT_METRICS)
--log.level="info" Only log messages with the given severity or above. Valid levels: [debug, info, warn, error, fatal]
--log.format="logger:stderr"
Set the log target and format. Example: "logger:syslog?appname=bob&local=7" or "logger:stdout?json=true"
--version Show application version.
This collector counts the number of DNS queries the DNS server receives by type. When enabled, it can break the number of DNS queries by type down by each client on the network.
IMPORTANT NOTE Be very careful when enabling the --stats.reverse-lookup
option on this collector. You MUST have a caching resolver (such as dnsmasq) configured on this system.
This is because the exporter does not cache reverse lookup information.
This means each line read from the log file will result in a DNS query to look the client up.
At best, this doubles the load on your DNS server.
At worst, it will cause an infinite lookup loop where a reverse lookup triggers a log entry, which triggers a reverse lookup, which triggers a log entry.
IMPORTANT NOTE Consider the size of your client network before enabling the capture-client
option.
See the note below in the Names collector for why this is a possible concern for your Prometheus installation.
bind_query_stats_total - Total queries recieved
bind_query_stats_total_by_type - Total queries recieved by type of query
bind_query_stats_by_client_and_type - Total queries recieved by type of query by client
This collector counts unique hits to individual DNS names by setting the metric bind_query_names_all{name="site.foo.bar.com",...} 123
.
If the --names.capture-clients
flag is set, the vector will also include the address of the client (or reverse lookup with --reverse-lookup
).
IMPORTANT NOTE: Each DNS name detected will gets its own label in the bind_query_names_all
vector.
Depending on the number of things matched, you may expose yourself to the cardinality problems mentioned here and here - especially if your nameserver is used as a recursive server or sees hits for many domains!
Consider using the includeFile as a permit list to limit what is gathered.
Because of this, the Names collector is not enabled by default.
bind_query_names_all - Queries per DNS name
bind_query_names_total - Sum of all queries matched. If no include/exclude filter is present, this will match bind_query_stats_total in the stats collector. It is initialized to 0 to support increment() detection.
Refer to the contributing guidelines.
Apache License 2.0, see LICENSE.