dnsperf(1)

NAME
dnsperf - test the performance of a DNS server

SYNOPSIS
dnsperf [-a local_addr] [-b bufsize] [-B] [-c clients] [-d datafile] [-D] [-e] [-E code:secret] [-f family] [-h] [-j] [-l limit] [-m mode] [-n runs_through_file] [-p port] [-q num_queries] [-Q max_qps] [-s server_addr] [-S stats_interval] [-t timeout] [-T threads] [-u] [-v] [-W] [-x local_port] [-y [alg:]name:secret] [-O option=value]

DESCRIPTION
dnsperf is a DNS server performance testing tool. It is primarily intended for measuring the performance of authoritative DNS servers, but it can also be used for measuring caching server performance in a closed laboratory environment. For testing caching servers resolving against the live Internet, the resperf program is preferred.

It is recommended that dnsperf and the name server under test be run on separate machines, so that the CPU usage of dnsperf itself does not slow down the name server. The two machines should be connected with a fast network, preferably a dedicated Gigabit Ethernet segment. Testing through a router or firewall is not advisable.

  Configuring the name server
If using dnsperf to test an authoritative server, the name server under test should be set up to serve one or more zones similar in size and number to what the server is expected to serve in production.

Also, be sure to turn off recursion in the server's configuration (in BIND 8/9, specify "recursion no;" in the options block). In BIND 8, you should also specify "fetch-glue no;"; otherwise the server may attempt to retrieve glue information from the Internet during the test, slowing it down by an unpredictable factor.

  Constructing a query input file
A dnsperf input file should contain a large and realistic set of queries, on the order of ten thousand to a million. The input file contains one line per query, consisting of a domain name and an RR type name separated by a space. The class of the query is implicitly IN.

When measuring the performance serving non-terminal zones such as the root zone or TLDs, note that such servers spend most of their time providing referral responses, not authoritative answers. Therefore, a realistic input file might consist mostly of queries for type A for names *below*, not at, the delegations present in the zone. For example, when testing the performance of a server configured to be authoritative for the top-level domain "fi.", which contains delegations for domains like "helsinki.fi" and "turku.fi", the input file could contain lines like

    www.turku.fi A
    www.helsinki.fi A

where the "www" prefix ensures that the server will respond with a referral. Ideally, a realistic proportion of queries for nonexistent domains should be mixed in with those for existing ones, and the lines of the input file should be in a random order.

To use space and dot, and any other character, in the domain name you can quote them using \\DDD where each D is a digit is the octet corresponding to the decimal number described by DDD (as per RFC1035 5.1. Format). Dots can be quoted without converting, for example:

    space\032space.com A
    tab\009tab.com A
    dot\.dot.com A

  Constructing a dynamic update input file
To test dynamic update performance, dnsperf is run with the -u option, and the input file is constructed of blocks of lines describing dynamic update messages. The first line in a block contains the zone name:

    example.com

Subsequent lines contain prerequisites, if there are any. Prerequisites can specify that a name may or may not exist, an rrset may or may not exist, or an rrset exists and its rdata matches all specified rdata for that name and type. The keywords "require" and "prohibit" are followed by the appropriate information. All relative names are considered to be relative to the zone name. The following lines show the 5 types of prerequisites.

    require a
    require a A
    require a A 1.2.3.4
    prohibit x
    prohibit x A

Subsequent lines contain records to be added, records to be deleted, rrsets to be deleted, or names to be deleted. The keywords "add" or "delete" are followed by the appropriate information. All relative names are considered to be relative to the zone name. The following lines show the 4 types of updates.

    add x 3600 A 10.1.2.3
    delete y A 10.1.2.3
    delete z A
    delete w

Each update message is terminated by a line containing the command:

    send

  Running the tests
When running dnsperf, a data file (the -d option) and server (the -s option) will normally be specified. The output of dnsperf is mostly self-explanatory. Pay attention to the number of dropped packets reported - when running the test over a local Ethernet connection, it should be zero. If one or more packets has been dropped, there may be a problem with the network connection. In that case, the results should be considered suspect and the test repeated.

  Using DNS-over-HTTPS
When using DNS-over-HTTPS you must set the -O doh-uri=... to something that works with the server you're sending to. Also note that the value for maximum outstanding queries will be used to control the maximum concurrent streams within the HTTP/2 connection.

OPTIONS

-a local_addr
    Specifies the local address from which to send requests. The default is the wildcard address.

-b bufsize
    Sets the size of the socket's send and receive buffers, in kilobytes. If not specified, the operating system's default is used.

-B
    Instructs dnsperf to read datafile in TCP-stream binary format as specified by RFC 1035 section "4.2.2. TCP usage". Each packet is preceded by 2-byte preambule which specifies length of the following DNS packet in network byte order, immediatelly followed by raw bytes of the packet. First two bytes of any packet should contain message ID and are overwritten by dnsperf on the fly. All other bytes are left intact. Packets shorter than two bytes are sent intact. Packets in datafile can contain arbitrary bytes and are not checked for validity. Malformed packets probably will not be responded to by servers and will cause timeouts. This option is mutually exclusive with -D, -e, -E, -u and -y.

    These binary datafiles can be generated using arbitrary TCP listeners such as netcat (nc) and sockat. TCP must be used so that the length is prepended. Following example shows how to generate a datafile with two query and then using it, you need two terminals.

        (terminal 1) $ nc -l 127.0.0.1 5300 > dns.blob
        (terminal 2) $ echo "example.com A" | dnsperf -s 127.0.0.1 -p 5300 -m tcp
        (terminal 1) $ nc -l 127.0.0.1 5300 >> dns.blob
        (terminal 2) $ echo "example.com AAAA" | dnsperf -s 127.0.0.1 -p 5300 -m tcp
        (terminal 1) $ dnsperf -B -d dns.blob -s $IP

-c clients
    Act as multiple clients. Requests are sent from multiple sockets. The default is to act as 1 client.

-d datafile
    Specifies the input data file. If not specified, dnsperf will read from standard input.

-D
    Sets the DO (DNSSEC OK) bit [RFC3225] in all packets sent. This also enables EDNS0, which is required for DNSSEC. This option is mutually exclusive with -B.

-e
    Enables EDNS0 [RFC2671], by adding an OPT record to all packets sent. This option is mutually exclusive with -B.

-E code:value
    Add an EDNS [RFC2671] option to all packets sent, using the specified numeric option code and value expressed as a a hex-encoded string. This also enables EDNS0. This option is mutually exclusive with -B.

-f family
    Specifies the address family used for sending DNS packets. The possible values are "inet", "inet6", or "any". If "any" (the default value) is specified, dnsperf will use whichever address family is appropriate for the server it is sending packets to.

-h
    Print a usage statement and exit.

-j
    NOTE: Only available if built-in!

    Output streaming JSON objects for progress and statistics, see section JSON OUTPUT for full details.

        $ src/dnsperf -d ../src/test/datafile -s 172.17.0.1 -j -S1 -Q1 -n 2
        {"start":{"version":"2.14.0","command_line":["dnsperf","-d","../src/test/datafile","-s","172.17.0.1","-j","-S1","-Q1","-n","2"],"queries":true,"server_addr":"172.17.0.1","server_port":53,"started":"Thu Dec 18 08:41:05 2025","maxruns":2}}
        {"rate":{"timestamp_usec":1766047266411099,"qps":0.99872063886161822}}
        {"rate":{"timestamp_usec":1766047267412462,"qps":1.997277710480615}}
        {"rate":{"timestamp_usec":1766047268413677,"qps":0.99878647443356328}}
        {"stop":{"reason":"end of file"}}
        {"statistics":{"sent":4,"completed":4,"lost":0,"request_avg_pktsize":28,"response_avg_pktsize":50,"run_time":4.0,"qps":0.99992450569981972,"latency":{"avg":0.02145,"min":0.00026400000000000002,"max":0.042937000000000003,"stddev":0.024424912669581168}}}

    Can be used together with extended options verbose-interval-stats and latency-histogram.

    This option is currently not compatible together with -v or -W.

-l limit
    Specifies a time limit for the run, in seconds. This may cause the input to be read multiple times, or only some of the input to be read. The default behavior is to read the input once, and have no specific time limit.

-m mode
    Specifies the transport mode to use, "udp", "tcp", "dot" or "doh". Default is "udp".

-n runs_through_file
    Run through the input file at most this many times. If no time limit is set, the file will be read exactly this number of times; if a time limit is set, the file may be read fewer times.

-p port
    Sets the port on which the DNS packets are sent. If not specified, the standard DNS port (udp/tcp 53, DoT 853, DoH 443) is used.

-q num_queries
    Sets the maximum number of outstanding requests. When this value is reached, dnsperf will not send any more requests until either responses are received or requests time out. The default value is 100.

-Q max_qps
    Limits the number of requests per second. There is no default limit.

-s server_addr
    Specifies the name or address of the server to which requests will be sent. The default is the loopback address, 127.0.0.1.

-S stats_interval
    If this parameter is specified, a count of the number of answers received per second during the interval will be printed out every stats_interval seconds.

-t timeout
    Specifies the request timeout value, in seconds. dnsperf will no longer wait for a response to a particular request after this many seconds have elapsed. The default is 5 seconds.

-T threads
    Run multiple client threads. By default, dnsperf uses one thread for sending requests and one thread for receiving responses. If this option is specified, dnsperf will instead use N pairs of send/receive threads.

-u
    Instructs dnsperf to send DNS dynamic update messages, rather than queries. The format of the input file is different in this case; see the "Constructing a dynamic update input file" section for more details. This option is mutually exclusive with -B.

-v
    Enables verbose mode. The DNS RCODE of each response will be reported to standard output when the response is received, as will the latency. If a query times out, it will be reported with the special string "T" instead of a normal DNS RCODE. If a query is interrupted, it will be reported with the special string "I". Additional information regarding network readiness and congestion will also be reported.

-W
    Log warnings and errors to standard output instead of standard error making it easier for script, test and automation to capture all output.

-x local_port
    Specifies the local port from which to send requests. The default is the wildcard port (0).

    If acting as multiple clients and the wildcard port is used, each client will use a different random port. If a port is specified, the clients will use a range of ports starting with the specified one.

-y [alg:]name:secret
    Add a TSIG record [RFC2845] to all packets sent, using the specified TSIG key algorithm, name and secret, where the algorithm defaults to hmac-md5 and the secret is expressed as a base-64 encoded string. Available algorithms are: hmac-md5, hmac-sha1, hmac-sha224, hmac-sha256, hmac-sha384 and hmac-sha512. This option is mutually exclusive with -B.

-O option=value
    Set an extended long option for various things to control different aspects of testing or protocol modules, see EXTENDED OPTIONS for list of available options.

EXTENDED OPTIONS

doh-uri=URI
    The URI to use for DNS-over-HTTPS, default value is "https://localhost/dns-query".

doh-method=HTTP_METHOD
    The HTTP method to use when querying with DNS-over-HTTPS, default is GET. Available methods are: GET, POST.

tls-sni=SERVER_NAME
    The Server Name Indication (SNI) to use for TLS connections (such as DNS-over-TLS or DNS-over-HTTPS), defaults to leaving out the SNI extension in the client hello.

suppress=MESSAGE[,MESSAGE,...]
    Suppress various messages and warnings that may be shown excessively in some situations, such as socket readiness when connecting to a slow service. Can suppress multiple types by listing them as a comma separated list. Following type are available.

    timeouts: Suppress messages about queries being timed out
    congestion: Suppress messages about network congestion
    sendfailed: Suppress messages about failure to send packets or if only parts of the packet were sent
    sockready: Suppress messages about socket readiness
    unexpected: Suppress messages about answers with an unexpected message ID
num-queries-per-conn=NUMBER
    This will limit the number of queries sent over a connection before triggering a re-connection. Once re-connected it will reset the counter and continue sending queries until the limit is reached again, triggering another re-connection and so on. Using this option will also enable counting number of responses received for each connection and once the limit is reached for sending queries it will wait until the same amount of responses has been received before re-connecting. Waiting for responses may timeout and the timeout used for this is the same as specified by -t. Note that this option is only useful for connection oriented protocols.

verbose-interval-stats
    Change the statistics format of -S to that shown at end of run.

    Please note: Min/max values for latency and connections are not available in interval statistics. Number of answers received within stats_interval can legitimately exceed number of queries sent, depending on answer latency, configured timeout, and stats_interval.

    Only available in dnsperf.

latency-histogram
    Print detailed latency histograms for DNS answers and connections. Latency is quantized into bins with roughly 3 % resolution, and latency range for individual bins increases logarithmically. This is done to to limit amount of memory required for histograms and also allows to visualize latency using logarithmic percentile histograms with minimal postprocessing.

    Only available in dnsperf and if compile time support was detected.

qps-threshold-wait=<microseconds>
    When using -Q to rate limit queries sent, this option control the minimum time (in microseconds) there should be between queries to use nanosleep() to wait until sending the next query. Setting to zero (0) will disable any call to nanosleep() between sending queries.

    If the time between queries is lower then this, then no wait is performed in order to have more precision on when to send the next query. This is because during high QPS rate limiting it can take more time just calling the functions to wait for when to send the next query then the actually time between queries.

    If not set, the average call-time to nanosleep() will be measured during startup.

    Only available in dnsperf.

JSON OUTPUT
Following data is available in the JSON output, dot is a delimiter for objects.

start.version=string
    The version of dnsperf that generated the JSON.

start.command_line=[string,...]
    The executed command and it's options as an array of strings.

start.updates=boolean
    Set to true if what's was sent was dynamic updates.

start.queries=boolean
    Set to true if what's was sent was DNS queries.

start.server_addr=string
    The server address sent to.

start.server_port=int
    The server port sent to.

start.started=string
    Date and time when execution started.

start.timelimit=double
    Set to a number of seconds if execution was limited to that.

start.maxruns=int
    Set to a number of runs if execution was limited to that.

rate.timestamp_usec=uint
    Current UNIX timestamp in microseconds.

rate.qps=double
    Current queries per second sent.

stop.reason=string
    The reason the execution was stopped.

statistics.interval=boolean
    Set to true if this statistics object was outputted as requested by the extended option verbose-interval-stats.

statistics.sent=uint
    The number of queries sent.

statistics.completed=uint
    The number of responses received for queries sent.

statistics.lost=uint
    The number of queries that didn't receive a response, either timed out or by other means.

statistics.interrupted=uint
    The number of queries that was in some way interruped.

statistics.unexpected=uint
    The number of responses received that did not have a corresponding query.

statistics.request_avg_pktsize=uint
    Average packet size for queries.

statistics.response_avg_pktsize=uint
    Average packet size for responses.

statistics.runtime=double
    The run time in seconds.

statistics.qps=double
    The queries per second.

statistics.latency=latency
    A query/response latency object, see below.

statistics.connection.attempts=uint
    The number of connection attempts made.

    Only available when using connection oriented protocols.

statistics.connection.completed=uint
    The number of connections established.

    Only available when using connection oriented protocols.

statistics.connection.latency=latency
    A connection latency object, see below.

    Only available when using connection oriented protocols.

dns_over_https.status_codes={ http_status_code: count, ... }
    Specific statistics when DNS-over-HTTPS protocol is used.

    An object with a counter for each of the HTTP Status codes received.

latency.avg=double
    Average latency.

latency.min=double
    Minimum latency.

latency.max=double
    Maximum latency

latency.stddev=double
    Standard deviation of the latency.

latency.histogram=histogram
    A histogram of the latency, see below.

histogram=[[min, max, count],...]
    A histogram object, see extended option latency-histogram for more information.

SEE ALSO
resperf(1)

AUTHOR
Nominum, Inc.

Maintained by DNS-OARC

    https://www.dns-oarc.net/

BUGS
For issues and feature requests please use:

    https://codeberg.org/DNS-OARC/dnsperf/issues

For question and help please use:

    admin@dns-oarc.net