queryperf.c revision e2cf0e8ff9ff37121518af5b34b9e4de7abbb47c
1b5a34533410ff4eaff0e5b5b110221a97e29cfcAutomatic Updater * Copyright (C) 2000, 2001 Nominum, Inc.
8804fd9936acd703073c4a75072852c38738a990Brian Wellington * Permission to use, copy, modify, and distribute this software for any
ec5347e2c775f027573ce5648b910361aa926c01Automatic Updater * purpose with or without fee is hereby granted, provided that the above
8804fd9936acd703073c4a75072852c38738a990Brian Wellington * copyright notice and this permission notice appear in all copies.
8804fd9936acd703073c4a75072852c38738a990Brian Wellington * THE SOFTWARE IS PROVIDED "AS IS" AND INTERNET SOFTWARE CONSORTIUM
dafcb997e390efa4423883dafd100c975c4095d6Mark Andrews * DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL
dafcb997e390efa4423883dafd100c975c4095d6Mark Andrews * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL
dafcb997e390efa4423883dafd100c975c4095d6Mark Andrews * INTERNET SOFTWARE CONSORTIUM BE LIABLE FOR ANY SPECIAL, DIRECT,
dafcb997e390efa4423883dafd100c975c4095d6Mark Andrews * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING
dafcb997e390efa4423883dafd100c975c4095d6Mark Andrews * FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT,
dafcb997e390efa4423883dafd100c975c4095d6Mark Andrews * NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION
dafcb997e390efa4423883dafd100c975c4095d6Mark Andrews * WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
ab023a65562e62b85a824509d829b6fad87e00b1Rob Austein *** DNS Query Performance Testing Tool (queryperf.c)
8804fd9936acd703073c4a75072852c38738a990Brian Wellington *** Version $Id: queryperf.c,v 1.5 2002/07/22 02:47:24 marka Exp $
8804fd9936acd703073c4a75072852c38738a990Brian Wellington *** Stephen Jacob <sj@nominum.com>
8804fd9936acd703073c4a75072852c38738a990Brian Wellington * Configuration defaults
8804fd9936acd703073c4a75072852c38738a990Brian Wellington#define DEF_QUERY_TIMEOUT 5 /* in seconds */
8804fd9936acd703073c4a75072852c38738a990Brian Wellington * Other constants / definitions
8804fd9936acd703073c4a75072852c38738a990Brian Wellington#define HARD_TIMEOUT_EXTRA 5 /* in seconds */
8804fd9936acd703073c4a75072852c38738a990Brian Wellington#define RESPONSE_BLOCKING_WAIT_TIME 0.1 /* in seconds */
8804fd9936acd703073c4a75072852c38738a990Brian Wellingtonenum directives_enum { V_SERVER, V_PORT, V_MAXQUERIES, V_MAXWAIT };
8804fd9936acd703073c4a75072852c38738a990Brian Wellington#define DIRECTIVES { "server", "port", "maxqueries", "maxwait" }
8804fd9936acd703073c4a75072852c38738a990Brian Wellington#define DIR_VALUES { V_SERVER, V_PORT, V_MAXQUERIES, V_MAXWAIT }
8804fd9936acd703073c4a75072852c38738a990Brian Wellington "A", "NS", "MD", "MF", "CNAME", "SOA", "MB", "MG", \
8804fd9936acd703073c4a75072852c38738a990Brian Wellington "MR", "NULL", "WKS", "PTR", "HINFO", "MINFO", "MX", "TXT", \
8804fd9936acd703073c4a75072852c38738a990Brian Wellington "AAAA", "AXFR", "MAILB", "MAILA", "*", "ANY" \
8804fd9936acd703073c4a75072852c38738a990Brian Wellington "NOERROR", "FORMERR", "SERVFAIL", "NXDOMAIN", \
8804fd9936acd703073c4a75072852c38738a990Brian Wellington "NOTIMP", "REFUSED", "YXDOMAIN", "YXRRSET", \
8804fd9936acd703073c4a75072852c38738a990Brian Wellington "NXRRSET", "NOTAUTH", "NOTZONE", "rcode11", \
8804fd9936acd703073c4a75072852c38738a990Brian Wellington "rcode12", "rcode13", "rcode14", "rcode15" \
8804fd9936acd703073c4a75072852c38738a990Brian Wellington * Data type definitions
8804fd9936acd703073c4a75072852c38738a990Brian Wellington#define QUERY_STATUS_MAGIC 0x51535441U /* QSTA */
8804fd9936acd703073c4a75072852c38738a990Brian Wellington#define VALID_QUERY_STATUS(q) ((q) != NULL && \
8804fd9936acd703073c4a75072852c38738a990Brian Wellington unsigned short int id;
8804fd9936acd703073c4a75072852c38738a990Brian Wellington * Configuration options (global)
8804fd9936acd703073c4a75072852c38738a990Brian Wellingtonunsigned int max_queries_outstanding; /* init 0 */
8804fd9936acd703073c4a75072852c38738a990Brian Wellingtonunsigned int query_timeout = DEF_QUERY_TIMEOUT;
8804fd9936acd703073c4a75072852c38738a990Brian Wellingtonunsigned int socket_bufsize = DEF_BUFFER_SIZE;
e3e3bafa138a20558a2253470effc01702fc6dfdBrian Wellington * Other global stuff
e3e3bafa138a20558a2253470effc01702fc6dfdBrian Wellingtonunsigned int runs_through_file; /* init 0 */
8804fd9936acd703073c4a75072852c38738a990Brian Wellingtonunsigned int num_queries_outstanding; /* init 0 */
8804fd9936acd703073c4a75072852c38738a990Brian Wellingtonunsigned int num_queries_timed_out; /* init 0 */
8804fd9936acd703073c4a75072852c38738a990Brian Wellingtonstruct query_status *status; /* init NULL */
8804fd9936acd703073c4a75072852c38738a990Brian Wellingtonunsigned int query_status_allocated; /* init 0 */
8804fd9936acd703073c4a75072852c38738a990Brian Wellingtonstatic char *rcode_strings[] = RCODE_STRINGS;
13090db2b1c210b8386793ff0cbbb0b4348c1ecaBrian Wellington * get_uint16:
13090db2b1c210b8386793ff0cbbb0b4348c1ecaBrian Wellington * Get an unsigned short integer from a buffer (in network order)
13090db2b1c210b8386793ff0cbbb0b4348c1ecaBrian Wellingtonstatic unsigned short
93d6dfaf66258337985427c86181f01fc51f0bb4Mark Andrews unsigned short ret;
13090db2b1c210b8386793ff0cbbb0b4348c1ecaBrian Wellington * show_startup_info:
8804fd9936acd703073c4a75072852c38738a990Brian Wellington"DNS Query Performance Testing Tool\n"
8804fd9936acd703073c4a75072852c38738a990Brian Wellington"Version: $Id: queryperf.c,v 1.5 2002/07/22 02:47:24 marka Exp $\n"
8804fd9936acd703073c4a75072852c38738a990Brian Wellington * Print out usage/syntax information
8804fd9936acd703073c4a75072852c38738a990Brian Wellington"Usage: queryperf [-d datafile] [-s server_addr] [-p port] [-q num_queries]\n"
8804fd9936acd703073c4a75072852c38738a990Brian Wellington" [-b bufsize] [-t timeout] [-n] [-l limit] [-1]\n"
8804fd9936acd703073c4a75072852c38738a990Brian Wellington" -d specifies the input data file (default: stdin)\n"
8804fd9936acd703073c4a75072852c38738a990Brian Wellington" -s sets the server to query (default: %s)\n"
8804fd9936acd703073c4a75072852c38738a990Brian Wellington" -p sets the port on which to query the server (default: %u)\n"
8804fd9936acd703073c4a75072852c38738a990Brian Wellington" -q specifies the maximum number of queries outstanding (default: %d)\n"
8804fd9936acd703073c4a75072852c38738a990Brian Wellington" -t specifies the timeout for query completion in seconds (default: %d)\n"
8804fd9936acd703073c4a75072852c38738a990Brian Wellington" -n causes configuration changes to be ignored\n"
8804fd9936acd703073c4a75072852c38738a990Brian Wellington" -l specifies how a limit for how long to run tests in seconds (no default)\n"
a56f5ada432128085e4a06815328023ee0c9610dMark Andrews" -1 run through input only once (default: multiple iff limit given)\n"
8804fd9936acd703073c4a75072852c38738a990Brian Wellington" -b set input/output buffer size in kilobytes (default: %d k)\n"
8804fd9936acd703073c4a75072852c38738a990Brian Wellington" -e enable EDNS 0\n"
8804fd9936acd703073c4a75072852c38738a990Brian Wellington" -D set the DNSSEC OK bit (implies EDNS)\n"
8804fd9936acd703073c4a75072852c38738a990Brian Wellington" -c print the number of packets with each rcode\n"
8804fd9936acd703073c4a75072852c38738a990Brian Wellington" -v verbose: report the RCODE of each response on stdout\n"
a56f5ada432128085e4a06815328023ee0c9610dMark Andrews DEF_MAX_QUERIES_OUTSTANDING, DEF_QUERY_TIMEOUT,
a56f5ada432128085e4a06815328023ee0c9610dMark Andrews * set_datafile:
a56f5ada432128085e4a06815328023ee0c9610dMark Andrews * Set the datafile to read
a56f5ada432128085e4a06815328023ee0c9610dMark Andrews * Return -1 on failure
13090db2b1c210b8386793ff0cbbb0b4348c1ecaBrian Wellington * Return a non-negative integer otherwise
13090db2b1c210b8386793ff0cbbb0b4348c1ecaBrian Wellington if ((new_file == NULL) || (new_file[0] == '\0')) {
13090db2b1c210b8386793ff0cbbb0b4348c1ecaBrian Wellington fprintf(stderr, "Error: null datafile name\n");
13090db2b1c210b8386793ff0cbbb0b4348c1ecaBrian Wellington if ((dfname_tmp = malloc(strlen(new_file) + 1)) == NULL) {
13090db2b1c210b8386793ff0cbbb0b4348c1ecaBrian Wellington fprintf(stderr, "Error allocating memory for datafile name: "
a56f5ada432128085e4a06815328023ee0c9610dMark Andrews return (-1);
8804fd9936acd703073c4a75072852c38738a990Brian Wellington * set_input_stdin:
8804fd9936acd703073c4a75072852c38738a990Brian Wellington * Set the input to be stdin (instead of a datafile)
13090db2b1c210b8386793ff0cbbb0b4348c1ecaBrian Wellington * set_server:
13090db2b1c210b8386793ff0cbbb0b4348c1ecaBrian Wellington * Set the server to be queried
13090db2b1c210b8386793ff0cbbb0b4348c1ecaBrian Wellington * Return -1 on failure
13090db2b1c210b8386793ff0cbbb0b4348c1ecaBrian Wellington * Return a non-negative integer otherwise
8804fd9936acd703073c4a75072852c38738a990Brian Wellington /* If no change in server name, don't do anything... */
8804fd9936acd703073c4a75072852c38738a990Brian Wellington if ((server_to_query != NULL) && (new_name != NULL))
8804fd9936acd703073c4a75072852c38738a990Brian Wellington if (strcmp(new_name, server_to_query) == 0)
8804fd9936acd703073c4a75072852c38738a990Brian Wellington if ((new_name == NULL) || (new_name[0] == '\0')) {
8804fd9936acd703073c4a75072852c38738a990Brian Wellington fprintf(stderr, "Error: null server name\n");
368b37b616234fce3d23099eb180f1dd38e1fb62Mark Andrews return (-1);
8804fd9936acd703073c4a75072852c38738a990Brian Wellington if ((server_to_query = malloc(strlen(new_name) + 1)) == NULL) {
a56f5ada432128085e4a06815328023ee0c9610dMark Andrews fprintf(stderr, "Error allocating memory for server name: "
e407562a75eb93073bb72089cced150d7ffe4d4fTatuya JINMEI 神明達哉 if ((server_he = gethostbyname(new_name)) == NULL) {
8804fd9936acd703073c4a75072852c38738a990Brian Wellington fprintf(stderr, "Error: gethostbyname(\"%s\") failed\n",
8804fd9936acd703073c4a75072852c38738a990Brian Wellington qaddr.sin_addr = *((struct in_addr *)server_he->h_addr);
8804fd9936acd703073c4a75072852c38738a990Brian Wellington * set_server_port:
8804fd9936acd703073c4a75072852c38738a990Brian Wellington * Set the port on which to contact the server
8804fd9936acd703073c4a75072852c38738a990Brian Wellington * Return -1 if port is invalid
8804fd9936acd703073c4a75072852c38738a990Brian Wellington * Return a non-negative integer otherwise
a56f5ada432128085e4a06815328023ee0c9610dMark Andrews return (-1);
8804fd9936acd703073c4a75072852c38738a990Brian Wellington * Tests if a character is a digit
e3e3bafa138a20558a2253470effc01702fc6dfdBrian Wellington * Return TRUE if it is
8804fd9936acd703073c4a75072852c38738a990Brian Wellington * Return FALSE if it is not
8804fd9936acd703073c4a75072852c38738a990Brian Wellington * Tests if a string, test_int, is a valid unsigned integer
8804fd9936acd703073c4a75072852c38738a990Brian Wellington * Sets *result to be the unsigned integer if it is valid
8804fd9936acd703073c4a75072852c38738a990Brian Wellington * Return TRUE if it is
8804fd9936acd703073c4a75072852c38738a990Brian Wellington * Return FALSE if it is not
8804fd9936acd703073c4a75072852c38738a990Brian Wellingtonis_uint(char *test_int, unsigned int *result) {
8804fd9936acd703073c4a75072852c38738a990Brian Wellington unsigned long int value;
8804fd9936acd703073c4a75072852c38738a990Brian Wellington if ((errno == ERANGE) || (*end != '\0') || (value > UINT_MAX))
8804fd9936acd703073c4a75072852c38738a990Brian Wellington * set_max_queries:
8804fd9936acd703073c4a75072852c38738a990Brian Wellington * Set the maximum number of outstanding queries
8804fd9936acd703073c4a75072852c38738a990Brian Wellington * Returns -1 on failure
8804fd9936acd703073c4a75072852c38738a990Brian Wellington * Returns a non-negative integer otherwise
8804fd9936acd703073c4a75072852c38738a990Brian Wellington static unsigned int size_qs = sizeof(struct query_status);
e3e3bafa138a20558a2253470effc01702fc6dfdBrian Wellington fprintf(stderr, "Unable to change max outstanding queries: "
13090db2b1c210b8386793ff0cbbb0b4348c1ecaBrian Wellington "must be positive and non-zero: %u\n", new_max);
8804fd9936acd703073c4a75072852c38738a990Brian Wellington temp_stat = realloc(status, new_max * size_qs);
8804fd9936acd703073c4a75072852c38738a990Brian Wellington fprintf(stderr, "Error resizing query_status\n");
8804fd9936acd703073c4a75072852c38738a990Brian Wellington * Be careful to only initialise between above
8804fd9936acd703073c4a75072852c38738a990Brian Wellington * the previously allocated space. Note that the
f3ca27e9fe307b55e35ea8d7b37351650630e5a3Andreas Gustafsson * allocation may be larger than the current
8804fd9936acd703073c4a75072852c38738a990Brian Wellington * max_queries_outstanding. We don't want to
8804fd9936acd703073c4a75072852c38738a990Brian Wellington * "forget" any outstanding queries! We might
df925e6c66d45d960fbac0383169763967d2111cEvan Hunt * still have some above the bounds of the max.
f3ca27e9fe307b55e35ea8d7b37351650630e5a3Andreas Gustafsson status[count].magic = QUERY_STATUS_MAGIC;
8804fd9936acd703073c4a75072852c38738a990Brian Wellington * parse_args:
8804fd9936acd703073c4a75072852c38738a990Brian Wellington * Parse program arguments and set configuration options
8804fd9936acd703073c4a75072852c38738a990Brian Wellington * Return -1 on failure
8804fd9936acd703073c4a75072852c38738a990Brian Wellington * Return a non-negative integer otherwise
8804fd9936acd703073c4a75072852c38738a990Brian Wellington while ((c = getopt(argc, argv, "q:t:nd:s:p:1l:b:eDcv")) != -1) {
8804fd9936acd703073c4a75072852c38738a990Brian Wellington if (is_uint(optarg, &uint_arg_val) == TRUE) {
8804fd9936acd703073c4a75072852c38738a990Brian Wellington fprintf(stderr, "Option requires a positive "
8804fd9936acd703073c4a75072852c38738a990Brian Wellington "integer value: -%c %s\n",
8804fd9936acd703073c4a75072852c38738a990Brian Wellington if (is_uint(optarg, &uint_arg_val) == TRUE) {
8804fd9936acd703073c4a75072852c38738a990Brian Wellington fprintf(stderr, "Option requires a positive "
8804fd9936acd703073c4a75072852c38738a990Brian Wellington "integer value: -%c %s\n",
8804fd9936acd703073c4a75072852c38738a990Brian Wellington if (is_uint(optarg, &uint_arg_val) == TRUE &&
8804fd9936acd703073c4a75072852c38738a990Brian Wellington fprintf(stderr, "Option requires a positive "
8804fd9936acd703073c4a75072852c38738a990Brian Wellington "integer between 0 and %d: -%c %s\n",
8804fd9936acd703073c4a75072852c38738a990Brian Wellington if (is_uint(optarg, &uint_arg_val) == TRUE) {
8804fd9936acd703073c4a75072852c38738a990Brian Wellington fprintf(stderr, "Option requires a positive "
8804fd9936acd703073c4a75072852c38738a990Brian Wellington "integer: -%c %s\n",
c, optarg);
open_datafile(void) {
close_datafile(void) {
open_socket(void) {
int sock;
int ret;
int bufsize;
if (ret < 0)
if (ret < 0)
close_socket(void) {
if (query_socket != 0) {
query_socket = 0;
argv[0]);
argv[0]);
show_usage();
double diff;
return diff;
timelimit_reached(void) {
return (FALSE);
return (FALSE);
return (TRUE);
< (double)run_timelimit)
return (FALSE);
return (TRUE);
return (FALSE);
return (TRUE);
return (TRUE);
return (FALSE);
queries_outstanding(void) {
return (num_queries_outstanding);
char *result;
unsigned int uint_val;
int directive_number;
int check;
switch(directive_number) {
case V_SERVER:
case V_PORT:
case V_MAXQUERIES:
case V_MAXWAIT:
int bytes_sent;
if (edns) {
if (dnssec)
static unsigned short int use_query_id = 0;
int query_type;
unsigned int count;
use_query_id++;
if (verbose)
int retval;
return (TRUE);
return (FALSE);
unsigned int ct = 0;
if (countrcodes)
int flags;
process_responses(void) {
retire_old_queries(void) {
unsigned int count = 0;
>= (double)query_timeout)) {
print_statistics(void) {
unsigned int num_queries_completed;
if (num_queries_completed == 0) {
/ (double)num_queries_sent;
if (num_queries_sent == 0) {
if (use_timelimit)
if (countrcodes) {
if (rcodecounts[i] == 0)
if (len == 0) {
close_socket();