nsprobe.c revision 11463c0ac24692e229ec87f307f5e7df3c0a7e10
/*
* Copyright (C) 2009-2014 Internet Systems Consortium, Inc. ("ISC")
*
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
* REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
* AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
* INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
* LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
* OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
* PERFORMANCE OF THIS SOFTWARE.
*/
/* $Id$ */
#include <config.h>
#ifndef WIN32
#include <unistd.h>
#include <netdb.h>
#endif
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <isc/commandline.h>
#include <isc/sockaddr.h>
#include <dns/fixedname.h>
#include <dns/rdataset.h>
#include <dns/rdatastruct.h>
#include <dns/rdatatype.h>
#define MAX_PROBES 1000
static unsigned int outstanding_probes = 0;
const char *cacheserver = "127.0.0.1";
typedef enum {
none,
lame,
struct server {
};
struct probe_ns {
struct server *current_server;
};
struct probe_trans {
char *domain;
const char **qlabel;
/* NS list */
struct probe_ns *current_ns;
};
struct lcl_stat {
unsigned long valid;
unsigned long ignore;
unsigned long nxdomain;
unsigned long othererr;
unsigned long multiplesoa;
unsigned long multiplecname;
unsigned long brokenanswer;
unsigned long lame;
unsigned long unknown;
static unsigned long number_of_domains = 0;
static unsigned long number_of_servers = 0;
static unsigned long multiple_error_domains = 0;
static int verbose_level = 0;
/* Dump an rdataset for debug */
static isc_result_t
isc_region_t r;
char t[4096];
if (!debug_mode)
return (ISC_R_SUCCESS);
isc_buffer_init(&target, t, sizeof(t));
return (ISC_R_SUCCESS);
&target);
if (result != ISC_R_SUCCESS)
return (result);
isc_buffer_usedregion(&target, &r);
return (ISC_R_SUCCESS);
}
static isc_result_t
isc_region_t r;
char t[4096];
isc_buffer_init(&target, t, sizeof(t));
if (result == ISC_R_SUCCESS) {
isc_buffer_usedregion(&target, &r);
} else
printf("(invalid name)");
return (result);
}
static isc_result_t
char buf[NI_MAXHOST];
NULL, 0, NI_NUMERICHOST) == 0) {
} else {
}
return (ISC_R_SUCCESS);
}
static void
{
if (*socketmgrp != NULL)
}
static isc_result_t
{
if (result != ISC_R_SUCCESS)
goto fail;
if (result != ISC_R_SUCCESS)
goto fail;
if (result != ISC_R_SUCCESS)
goto fail;
if (result != ISC_R_SUCCESS)
goto fail;
if (result != ISC_R_SUCCESS)
goto fail;
return (ISC_R_SUCCESS);
fail:
return (result);
}
/*
* Common routine to make query data
*/
static isc_result_t
{
if (result != ISC_R_SUCCESS)
goto cleanup;
if (result != ISC_R_SUCCESS)
goto cleanup;
return (ISC_R_SUCCESS);
return (result);
}
/*
* Update statistics
*/
static inline void
increment_entry(unsigned long *entryp) {
(*entryp)++;
}
static void
struct lcl_stat local_stat;
unsigned int err_count = 0;
const char *stattype;
/* Update per sever statistics */
/*
* Don't care about the result of A query if
* the answer to AAAA query was expected.
*/
stattype = "valid";
switch (server->result_aaaa) {
case exist:
case notype:
stattype = "valid";
break;
case timedout:
stattype = "ignore";
break;
case nxdomain:
stattype = "nxdomain";
break;
case othererr:
stattype = "othererr";
break;
case multiplesoa:
stattype = "multiplesoa";
break;
case multiplecname:
stattype = "multiplecname";
break;
case brokenanswer:
stattype = "brokenanswer";
break;
case lame:
stattype = "lame";
break;
default:
stattype = "unknown";
break;
}
} else {
stattype = "unknown";
}
if (verbose_level > 1 ||
(verbose_level == 1 &&
putchar('(');
stattype);
}
}
}
/* Update per domain statistics */
if (local_stat.ignore > 0U) {
if (verbose_level > 0)
err_count++;
}
if (local_stat.nxdomain > 0U) {
if (verbose_level > 0)
err_count++;
}
if (local_stat.othererr > 0U) {
if (verbose_level > 0)
err_count++;
}
if (local_stat.multiplesoa > 0U) {
if (verbose_level > 0)
err_count++;
}
if (local_stat.multiplecname > 0U) {
if (verbose_level > 0)
err_count++;
}
if (local_stat.brokenanswer > 0U) {
if (verbose_level > 0)
err_count++;
}
if (local_stat.lame > 0U) {
if (verbose_level > 0)
err_count++;
}
if (err_count > 1U)
/*
* We regard the domain as valid if and only if no authoritative server
* has a problem and at least one server is known to be valid.
*/
if (verbose_level > 1)
}
/*
* If the domain has no available server or all servers have the
* 'unknown' result, the domain's result is also regarded as unknown.
*/
if (verbose_level > 1)
}
}
/*
* Search for an existent name with an A RR
*/
static isc_result_t
unsigned int domainlen;
isc_buffer_t b;
return (ISC_R_NOMORE);
if (result != ISC_R_SUCCESS)
return (result);
if (result != ISC_R_SUCCESS)
return (result);
isc_buffer_add(&b, domainlen);
0, NULL);
return (result);
}
static void
INSIST(outstanding_probes > 0);
} else {
}
/* no error but empty answer */
} else {
while (result == ISC_R_SUCCESS) {
&name);
link)) {
/* Should chase the chain? */
goto found;
goto found;
}
}
}
/*
* Something unexpected happened: the response
* contained a non-empty authoritative answer, but we
* could not find an expected result.
*/
*resultp = unexpected;
}
/* Broken response. Try identifying known cases. */
*resultp = brokenanswer;
while (result == ISC_R_SUCCESS) {
/*
* Check to see if the response has multiple
* CNAME RRs. Update the result code if so.
*/
&name);
link)) {
*resultp = multiplecname;
goto found;
}
}
}
}
while (result == ISC_R_SUCCESS) {
/*
* Check to see if the response has multiple
* SOA RRs. Update the result code if so.
*/
&name);
link)) {
*resultp = multiplesoa;
goto found;
}
}
}
}
else {
*resultp = unexpected;
}
if (result == ISC_R_NOMORE) {
/* We've tried all addresses of all servers. */
/*
* If we've explored A RRs and found an existent
* record, we can move to AAAA.
*/
} else if (type == dns_rdatatype_a) {
/*
* No server provided an existent A RR of this name.
* Try next label.
*/
if (result == ISC_R_SUCCESS) {
trans->current_ns =
link)) {
none);
}
}
}
}
if (result != ISC_R_SUCCESS) {
/*
* We've explored AAAA RRs or failed to find a valid
* query label. Wrap up the result and move to the
* next domain.
*/
}
} else if (result != ISC_R_SUCCESS)
}
static isc_result_t
if ((type == dns_rdatatype_a &&
(type == dns_rdatatype_aaaa &&
goto found;
}
}
}
return (ISC_R_NOMORE);
if (result != ISC_R_SUCCESS)
return (result);
return (result);
}
/*
* Get IP addresses of NSes
*/
static void
INSIST(outstanding_probes > 0);
continue;
result == ISC_R_SUCCESS;
NULL);
if (result != ISC_R_SUCCESS)
continue;
"mem_get failed");
goto cleanup;
}
}
}
}
if (result == ISC_R_SUCCESS)
} else {
if (result != ISC_R_SUCCESS)
goto next_ns; /* XXX: this is unlikely to succeed */
}
if (result != ISC_R_SUCCESS)
}
static isc_result_t
}
/*
* Get NS RRset for a given domain
*/
static void
}
}
}
static void
INSIST(outstanding_probes > 0);
continue;
result == ISC_R_SUCCESS;
/*
* Extract the name from the NS record.
*/
if (result != ISC_R_SUCCESS)
continue;
"resolve_ns: mem_get failed");
/*
* XXX: should we continue with the
* available servers anyway?
*/
goto cleanup;
}
}
}
}
/* Go get addresses of NSes */
} else
if (result == ISC_R_SUCCESS)
return;
}
static isc_result_t
unsigned int domainlen;
isc_buffer_t b;
char *cp;
/* Construct domain */
return (ISC_R_NOMORE);
*cp = '\0';
"failed to allocate memory for domain: %s", cp);
return (ISC_R_NOMEMORY);
}
/* Start getting NS for the domain */
isc_buffer_add(&b, domainlen);
if (result != ISC_R_SUCCESS)
goto cleanup;
if (result != ISC_R_SUCCESS)
goto cleanup;
return (ISC_R_SUCCESS);
return (result);
}
ISC_PLATFORM_NORETURN_PRE static void
usage(void) ISC_PLATFORM_NORETURN_POST;
static void
usage(void) {
"[input_file]\n");
exit(1);
}
int
switch (ch) {
case 'c':
break;
case 'd':
break;
case 'h':
usage();
break;
case 'v':
break;
default:
usage();
break;
}
}
/* Common set up */
result = dns_lib_init();
if (result != ISC_R_SUCCESS) {
exit(1);
}
&timermgr);
if (result != ISC_R_SUCCESS) {
exit(1);
}
if (result != ISC_R_SUCCESS) {
exit(1);
}
/* Set local cache server */
if (error != 0) {
exit(1);
}
"assumption failure: addrlen is too long: %ld\n",
(long)res->ai_addrlen);
exit(1);
}
&servers);
if (result != ISC_R_SUCCESS) {
exit(1);
}
/* Create the main task */
probe_task = NULL;
if (result != ISC_R_SUCCESS) {
exit(1);
}
/* Open input file */
if (argc == 0)
else {
argv[0]);
exit(1);
}
}
/* Set up and start probe */
for (i = 0; i < MAX_PROBES; i++) {
if (result == ISC_R_SUCCESS) {
}
if (result != ISC_R_SUCCESS) {
exit(1);
}
}
for (i = 0; i < MAX_PROBES; i++) {
if (result == ISC_R_NOMORE)
break;
else if (result != ISC_R_SUCCESS) {
exit(1);
}
}
/* Start event loop */
/* Dump results */
printf("Per domain results (out of %lu domains):\n",
printf(" valid: %lu\n"
" ignore: %lu\n"
" nxdomain: %lu\n"
" othererr: %lu\n"
" multiplesoa: %lu\n"
" multiplecname: %lu\n"
" brokenanswer: %lu\n"
" lame: %lu\n"
" unknown: %lu\n"
" multiple errors: %lu\n",
printf("Per server results (out of %lu servers):\n",
printf(" valid: %lu\n"
" ignore: %lu\n"
" nxdomain: %lu\n"
" othererr: %lu\n"
" multiplesoa: %lu\n"
" multiplecname: %lu\n"
" brokenanswer: %lu\n"
" lame: %lu\n"
" unknown: %lu\n",
/* Cleanup */
for (i = 0; i < MAX_PROBES; i++) {
}
return (0);
}