1

I need to know the number of my DNS server clients. Probably it means unique IP's per day, or something, because i think there is no other way to identify clients in other way. So, i need to know how many clients my bind9 serves. How can i achieve that in simplest way?

2 Answers 2

3

1 - query logging

Enable query logging rndc querylog and parse your log files, like this:

grep -Eo "client ([0-9]{1,3}[\.]){3}[0-9]{1,3}" /path/to/logfile | sort -u | uniq
client 10.0.252.1
client 10.0.231.15
client 127.0.0.1

excluding duplicates | uniq and | wc -l to count them, but don't mind to find a real solution that will be really accurate and simply.


2 - dnstop

Capture traffic:

tcpdump -w dump.pcap -c 10000 port 53

Parse it:

dnstop dump.pcap > report.txt

Here is the output format (Only top 50 clients):

% cat report.txt
Sources          Count      %   cum%
------------ --------- ------ ------
10.0.252.1          36   87.8   87.8
10.0.250.100         3    7.3   95.1
10.0.231.15          2    4.9  100.0
[...]

3 - dnstap

There is also dnstap but I don't know much about it, except it is a BIND 9.11 planned feature : https://la51.icann.org/en/schedule/mon-tech/presentation-isc-bind-13oct14-en.pdf.


Edit: The command wasn't listing all IPs, I fixed it by adding sort -u.

Note: 'uniq' does not detect repeated lines unless they are adjacent.

6
  • It shows only top 50 clients? I need the exact number to know. Apr 17, 2015 at 8:08
  • Yes, unfortunately but there is no simply alternative that I know. Apr 17, 2015 at 8:19
  • Thats useful, but still not a solution. Apr 17, 2015 at 8:22
  • Thanks again, but rndc querylog looks like do nothing. It should append log data to /var/log/messages as i know, but file still empty. Apr 20, 2015 at 15:26
  • It depends of your OS/configuration and check in /var/log/syslog (Deb 7 - default). You can specify a path in configuration for querylog channel, using logging clause here : zytrax.com/books/dns/ch7/logging.html . Make sure query logging is ON, running rndc status. Apr 20, 2015 at 15:54
1

Fundamentally, the easiest way to get this information is from tcpdump. I've been doing something similar recently myself, but looking for different patterns. You may find some of what I have done to be useful for you.

http://distracted-it.blogspot.co.nz/search/label/dns http://distracted-it.blogspot.co.nz/2014/07/capturing-and-analysing-dns-samples.html

In particular, as described in "Capturing and Analysing DNS Samples (tcpdump meets SQLite3)", and putting it into a sqlite3 database is useful if you want to later ask further questions, but is not useful for live monitoring. The code for that can be found at https://github.com/cameronkerrnz/scriptorium/blob/master/dns-query-sample

Snapshot of the code:

#!/bin/bash

sample_size="50000"
interface="eth0"

echo "Capturing sample of $sample_size packets from interface $interface"

tcpdump -w /tmp/query-sample.pcap -i "$interface" -nn -p -c "$sample_size" -s0 dst port domain

rm -f /tmp/query-sample.sqlite3
sqlite3 /tmp/query-sample.sqlite3 'create table queries (count int,client,querytype,queryval);'

tcpdump -r /tmp/query-sample.pcap -nn \
    | sed -rne 's/^[^ ]+ IP ([0-9]+\.[0-9]+\.[0-9]+\.[0-9]+)\.[0-9]+ > ([0-9]+\.[0-9]+\.[0-9]+\.[0-9]+)\.[0-9]+: .* ([^?]+)\? ([A-Za-z0-9._-]+) .*/\1 \3 \4/p' \
    | awk '
        { queryval = $3 }
        queryval ~ /\.noisy-example\.com\.$/ { queryval = "SOMETHING.noisy-example.com." }
        queryval ~ /\.10\.in-addr\.arpa\.$/ { queryval = "SOMETHING.10.in-addr.arpa." }
        queryval ~ /\.67\.45\.123\.in-addr\.arpa\.$/ { queryval = "SOMETHING.67.45.123.in-addr.arpa." }
        queryval ~ /[0-9]*\.[0-9]*\.[0-9]*\.[0-9]*\.in-addr\.arpa\.$/ { queryval = "SOMETHING.in-addr.arpa." }
        { print $1,$2,queryval }' \
    | sort | uniq -c \
    | sed -re 's/[ \t]+/|/g' -e 's/^\|//' \
    | sqlite3 /tmp/query-sample.sqlite3 '.import /dev/stdin queries'

echo "
    In this report, Cost is a count of such queries received,
    normalised by the number of clients that queried it. Thus,
    something with a Cost greater than 10 (<= are omitted),
    would likely benefit from DNS caching.

    Some queries, namely inverse lookups and things under
    noisy-domain.com (generally some abuse of DNS) are
    aggregated.

"

sqlite3 /tmp/query-sample.sqlite3 <<EOF
.mode column
.header on

.width 4 7 70
select sum(count)/count(count) as Cost, querytype as RRtype, queryval as Name from queries group by RRtype,Name having Cost > 10 order by Cost desc limit 100;

.width 9 6 15
select sum(count) as NumQueries, querytype as RRtype, client as Client from queries group by Client having NumQueries > 10 order by NumQueries desc limit 100;
EOF

tcpdump -tt -r /tmp/query-sample.pcap -nn \
    | grep '\.53: ' \
    | cut -d. -f1 | uniq -c \
    | awk '
        NR == 1 {starttime = $2; next}
        {total += $1; count += 1; last = $1; lasttime = $2}
        END { total -= last; print "Queries / second = " total / (lasttime - starttime) }'

For live monitoring, you might care to use tcpdump and then process it with a solution such as sed and AWK, Python, Perl, etc. I've used sed and AWK recently to help me look for who is sending the most number of requests per second, which I then summarise with another to look for most-frequent-top-spikers. You should be able to re-utilise the first part at least (which I've just noticed I need to upload).

Finally, you'll want to make sure that in your reporting you don't abuse your own DNS server by calling dig too often. Use 'getent hosts' instead.

Example:

$ echo -e '1.1.1.1 2\n8.8.8.8 12\n8.8.4.4 25' \
  | awk '
    BEGIN {threshold = 5}
    $2 > threshold {
      "getent hosts " $1 | getline getent_hosts_str;
      split(getent_hosts_str, getent_hosts_arr, " ");
      print $1, getent_hosts_arr[2], $3
    }'
8.8.8.8 google-public-dns-a.google.com
8.8.4.4 google-public-dns-b.google.com

If you're looking for an ongoing solution that you can have a dashboard on top of, then you could use tcpdump and Python to emit per-second summarised report per client (to cut down on data) via JSON and push that towards an ELK stack. In Kibana 4 you can have it then chart the Unique Count of an attribute (such as clientip.raw)

Hope that gives you plenty of useful ideas.

Cheers, Cameron

2
  • Very nice, i'll give it a try little bit later and if it helps i'll mark the answer. Anyway much thanks to all of you. Apr 17, 2015 at 12:12
  • Hello Cameron, good answer, but please try to get a few examples from those links in your post, just in case those links become dead at a later time. This question may be relevant for a long time to come. Apr 21, 2015 at 10:45

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .