dighost.c revision d72952cf254b71c44e5e956a306016a5be9b9c38
/*
* Copyright (C) 2000-2017 Internet Systems Consortium, Inc. ("ISC")
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
*/
/*! \file
* \note
* Notice to programmers: Do not use this code as an example of how to
* use the ISC library to perform DNS lookups. Dig and Host both operate
* on the request level, since they allow fine-tuning of output and are
* intended as debugging tools. As a result, they perform many of the
* functions which could be better handled using the dns_resolver
* functions in most applications.
*/
#include <config.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <limits.h>
#ifdef HAVE_LOCALE_H
#include <locale.h>
#endif
#ifdef WITH_IDN
#endif
#ifdef DIG_SIGCHASE
#include <dns/callbacks.h>
#include <ctype.h>
#endif
#include <dns/fixedname.h>
#include <dns/rdataclass.h>
#include <dns/rdatalist.h>
#include <dns/rdataset.h>
#include <dns/rdatastruct.h>
#include <dns/rdatatype.h>
#include <isc/parseint.h>
#include <isc/sockaddr.h>
#include <isccfg/namedconf.h>
#include <bind9/getaddresses.h>
#ifdef PKCS11CRYPTO
#endif
#if ! defined(NS_INADDRSZ)
#define NS_INADDRSZ 4
#endif
#if ! defined(NS_IN6ADDRSZ)
#define NS_IN6ADDRSZ 16
#endif
static lwres_conf_t *lwconf;
unsigned int timeout = 0;
unsigned int extrabytes;
int sendcount = 0;
int recvcount = 0;
int sockcount = 0;
int ndots = -1;
int tries = 3;
int lookup_counter = 0;
static char servercookie[256];
#ifdef WITH_IDN
static void initialize_idn(void);
unsigned int used_org,
#define MAXDLEN 256
int idnoptions = 0;
#endif
/*%
* Exit Codes:
*
*\li 0 Everything went well, including things like NXDOMAIN
*\li 1 Usage error
*\li 7 Got too many RR's or Names
*\li 8 Couldn't open batch file
*\li 9 No reply from server
*\li 10 Internal error
*/
int exitcode = 0;
int fatalexit = 0;
char keynametext[MXNAME];
unsigned char cookie_secret[33];
unsigned char cookie[8];
unsigned int digestbits = 0;
#ifdef DIG_SIGCHASE
isc_result_t get_trusted_key(void);
int section);
void dump_database(void);
dns_name_t * name,
void clean_trustedkey(void);
#if DIG_SIGCHASE_BU
#endif
#if DIG_SIGCHASE_TD
#endif
#if DIG_SIGCHASE_TD
/*
* the current name is the parent name when we follow delegation
*/
/*
* the child name is used for delegation (NS DS responses in AUTHORITY section)
*/
#endif
#if DIG_SIGCHASE_BU
#endif
#if DIG_SIGCHASE_TD
#endif
#define MAX_TRUSTED_KEY 5
typedef struct struct_trusted_key_list {
int nb_tk;
#endif
#define DIG_MAX_ADDRESSES 20
/*%
* Apply and clear locks at the event level in global task.
* Can I get rid of these using shutdown events? XXX
*/
#define LOCK_LOOKUP {\
debug("success");\
}
#define UNLOCK_LOOKUP {\
"isc_mutex_unlock");\
}
/* dynamic callbacks */
#ifdef DIG_SIGCHASE
#endif
void
void
void
(*dighost_shutdown)(void);
/* forward declarations */
static void
static void
static void
static void
static void
static void
static isc_boolean_t
static void *
}
static void
}
char *
char *res;
do {
break;
} while (*res == '\0');
return (res);
}
static int
count_dots(char *string) {
char *s;
int i = 0;
s = string;
while (*s != '\0') {
if (*s == '.')
i++;
s++;
}
return (i);
}
static void
hex_dump(isc_buffer_t *b) {
unsigned int len, i;
isc_region_t r;
isc_buffer_usedregion(b, &r);
else
putchar('.');
}
printf("\n");
}
}
if (len % 16 != 0) {
for (i = len; (i % 16) != 0; i++)
else
putchar('.');
}
printf("\n");
}
}
/*%
* Append 'len' bytes of 'text' at '*p', failing with
* ISC_R_NOSPACE if that would advance p past 'end'.
*/
static isc_result_t
return (ISC_R_NOSPACE);
*p += len;
return (ISC_R_SUCCESS);
}
static isc_result_t
if (result != ISC_R_SUCCESS)
return (result);
if (result != ISC_R_SUCCESS)
return (result);
} else {
}
}
{
int r;
if (r > 0) {
/* This is a valid IPv6 address. */
unsigned int options = 0;
if (ip6_int)
if (result != ISC_R_SUCCESS)
return (result);
return (ISC_R_SUCCESS);
} else {
/*
* Not a valid IPv6 address. Assume IPv4.
* If 'strict' is not set, construct the
* in-addr.arpa name by blindly reversing
* octets whether or not they look like integers,
* so that this can be used for RFC2317 names
* and such.
*/
char *p = reverse;
return (DNS_R_BADDOTTEDQUAD);
if (result != ISC_R_SUCCESS)
return (result);
/* Append .in-addr.arpa. and a terminating NUL. */
if (result != ISC_R_SUCCESS)
return (result);
return (ISC_R_SUCCESS);
}
}
void
if (exitcode < 10)
exitcode = 10;
if (fatalexit != 0)
}
void
isc_time_t t;
if (debugging) {
if (debugtiming) {
TIME_NOW(&t);
isc_time_nanoseconds(&t) / 1000);
}
}
}
void
if (result != ISC_R_SUCCESS) {
}
}
/*%
* Create a server structure, which is part of the lookup structure.
* This is little more than a linked list of servers to query in hopes
* of finding the answer the user is looking for
*/
fatal("memory allocation failure in %s:%d",
return (srv);
}
static int
addr2af(int lwresaddrtype)
{
int af = 0;
switch (lwresaddrtype) {
case LWRES_ADDRTYPE_V4:
break;
case LWRES_ADDRTYPE_V6:
break;
}
return (af);
}
/*%
* Create a copy of the server list from the lwres configuration structure.
* The dest list must have already had ISC_LIST_INIT applied.
*/
static void
char tmp[sizeof("ffff:ffff:ffff:ffff:ffff:ffff:255.255.255.255") +
sizeof("%4000000000")];
int af;
int i;
debug("copy_server_list()");
continue;
continue;
char buf[sizeof("%4000000000")];
}
}
}
void
flush_server_list(void) {
dig_server_t *s, *ps;
debug("flush_server_list()");
s = ISC_LIST_HEAD(server_list);
while (s != NULL) {
ps = s;
s = ISC_LIST_NEXT(s, link);
}
}
void
set_nameserver(char *opt) {
int count, i;
char tmp[ISC_NETADDR_FORMATSIZE];
return;
if (result != ISC_R_SUCCESS)
fatal("couldn't get address for '%s': %s",
for (i = 0; i < count; i++) {
fatal("memory allocation failure");
}
}
static isc_result_t
return (ISC_R_FAILURE);
switch (af) {
case AF_INET:
break;
case AF_INET6:
break;
default:
return (ISC_R_FAILURE);
}
return (ISC_R_SUCCESS);
}
return (ISC_R_FAILURE);
}
/*%
* Produce a cloned server list. The dest list must have already had
* ISC_LIST_INIT applied.
*/
void
debug("clone_server_list()");
}
}
/*%
* Create an empty lookup structure, which holds all the information needed
* to get an answer to a user's question. This structure contains two
* linked lists: the server list (servers to query) and the query list
* (outstanding queries which have been made to the listed servers).
*/
make_empty_lookup(void) {
debug("make_empty_lookup()");
fatal("memory allocation failure in %s:%d",
looknew->ixfr_serial = 0;
#ifdef WITH_IDN
#else
#endif
#ifdef DIG_SIGCHASE
#if DIG_SIGCHASE_TD
#endif
#endif
looknew->ednsoptscnt = 0;
ISC_LIST_INIT(looknew->q);
return (looknew);
}
/*%
* Clone a lookup, perhaps copying the server list. This does not clone
* the query list, since it will be regenerated by the setup_lookup()
* function, nor does it queue up the new lookup for processing.
* Caution: If you don't clone the servers, you MUST clone the server
* list separately from somewhere else, or construct it by hand.
*/
debug("clone_lookup()");
looknew = make_empty_lookup();
#if DIG_SIGCHASE_TD
#endif
#ifdef DIG_SIGCHASE
#if DIG_SIGCHASE_TD
#endif
#endif
fatal("out of memory");
}
if (servers)
return (looknew);
}
/*%
* Requeue a lookup for further processing, perhaps copying the server
* list. The new lookup structure is returned to the caller, and is
* queued for processing. If servers are not cloned in the requeue, they
* must be added before allowing the current event to complete, since the
* completion of the event may result in the next entry on the lookup
* queue getting run.
*/
debug("requeue_lookup()");
if (lookup_counter > LOOKUP_LIMIT)
fatal("too many lookups");
debug("before insertion, init@%p -> %p, new@%p -> %p",
debug("after insertion, init -> %p, new = %p, new -> %p",
return (looknew);
}
void
setup_text_key(void) {
unsigned int secretsize;
unsigned char *secretstore;
debug("setup_text_key()");
if (secretstore == NULL)
fatal("memory allocation failure in %s:%d",
if (result != ISC_R_SUCCESS)
goto failure;
goto failure;
}
if (result != ISC_R_SUCCESS)
goto failure;
if (result != ISC_R_SUCCESS)
printf(";; Couldn't create key %s: %s\n",
else
}
static isc_result_t
isc_uint32_t n;
if (result != ISC_R_SUCCESS) {
return (result);
}
*uip = n;
return (ISC_R_SUCCESS);
}
const char *desc) {
}
const char *desc) {
}
static isc_uint32_t
if (result != ISC_R_SUCCESS)
fatal("couldn't parse digest bits");
return (tmp);
}
char buf[sizeof("xxxx:xxxx:xxxx:xxxx:xxxx:xxxx:XXX.XXX.XXX.XXX/128")];
fatal("out of memory");
prefix_length = 0;
goto done;
}
*slash = '\0';
if (result != ISC_R_SUCCESS) {
fatal("invalid prefix length in '%s': %s\n",
}
}
if (prefix_length > 128)
prefix_length = 128;
if (prefix_length > 32)
prefix_length = 32;
} else if (prefix_parsed) {
int i;
break;
}
}
if (prefix_length > 32)
prefix_length = 32;
}
if (!parsed)
done:
return (ISC_R_SUCCESS);
}
/*
* Parse HMAC algorithm specification
*/
void
parse_hmac(const char *hmac) {
char buf[20];
digestbits = 0;
#ifndef PK11_MD5_DISABLE
} else
#endif
digestbits = 0;
} else {
"invalid TSIG algorithm %s\n", buf);
}
}
/*
* Get a key from a named.conf format keyfile
*/
static isc_result_t
read_confkey(void) {
const char *keyname;
const char *secretstr;
const char *algorithm;
if (! isc_file_exists(keyfile))
return (ISC_R_FILENOTFOUND);
if (result != ISC_R_SUCCESS)
goto cleanup;
&file);
if (result != ISC_R_SUCCESS)
goto cleanup;
if (result != ISC_R_SUCCESS)
goto cleanup;
fatal("key must have algorithm and secret");
}
return (result);
}
void
setup_file_key(void) {
debug("setup_file_key()");
/* Try reading the key from a K* pair */
&dstkey);
/* If that didn't work, try reading it as a session.key keyfile */
if (result != ISC_R_SUCCESS) {
result = read_confkey();
if (result == ISC_R_SUCCESS)
return;
}
if (result != ISC_R_SUCCESS) {
goto failure;
}
switch (dst_key_alg(dstkey)) {
#ifndef PK11_MD5_DISABLE
case DST_ALG_HMACMD5:
break;
#endif
case DST_ALG_HMACSHA1:
break;
case DST_ALG_HMACSHA224:
break;
case DST_ALG_HMACSHA256:
break;
case DST_ALG_HMACSHA384:
break;
case DST_ALG_HMACSHA512:
break;
default:
printf(";; Couldn't create key %s: bad algorithm\n",
goto failure;
}
if (result != ISC_R_SUCCESS) {
printf(";; Couldn't create key %s: %s\n",
goto failure;
}
}
static dig_searchlist_t *
make_searchlist_entry(char *domain) {
fatal("memory allocation failure in %s:%d",
return (search);
}
static void
clear_searchlist(void) {
}
}
static void
int i;
debug("create_search_list()");
}
}
/*%
* Setup the system as a whole, reading key information and resolv.conf
* settings.
*/
void
unsigned int lwresflags;
debug("setup_system()");
if (ipv4only) {
if (have_ipv4) {
} else {
fatal("can't find IPv4 networking");
}
}
if (ipv6only) {
if (have_ipv6) {
} else {
fatal("can't find IPv6 networking");
}
}
if (have_ipv4)
if (have_ipv6)
if (lwresult != LWRES_R_SUCCESS)
fatal("lwres_context_create failed");
/* Make the search list */
else { /* No search list. Use the domain name if any */
}
}
debug("verbose is on");
}
if (ndots == -1) {
}
if (tries < 2)
tries = 2;
}
}
/* If user doesn't specify server use nameservers from resolv.conf. */
if (ISC_LIST_EMPTY(server_list))
/* If we don't find a nameserver fall back to localhost */
if (ISC_LIST_EMPTY(server_list)) {
if (have_ipv4) {
if (lwresult != ISC_R_SUCCESS)
fatal("add_nameserver failed");
}
if (have_ipv6) {
if (lwresult != ISC_R_SUCCESS)
fatal("add_nameserver failed");
}
}
#ifdef WITH_IDN
#endif
if (keyfile[0] != 0)
else if (keysecret[0] != 0)
#ifdef DIG_SIGCHASE
/* Setup the list of messages for +sigchase */
#if DIG_SIGCHASE_TD
#endif
#if DIG_SIGCHASE_BU
#endif
#endif
sizeof(cookie_secret), NULL, 0);
if (result != ISC_R_SUCCESS)
fatal("unable to generate cookie secret");
}
/*%
* Override the search list derived from resolv.conf by 'domain'.
*/
void
set_search_domain(char *domain) {
}
/*%
* Setup the ISC and DNS libraries for use by the system.
*/
void
setup_libs(void) {
debug("setup_libs()");
#ifdef PKCS11CRYPTO
#endif
result = isc_net_probeipv4();
if (result == ISC_R_SUCCESS)
result = isc_net_probeipv6();
if (result == ISC_R_SUCCESS)
fatal("can't find either v4 or v6 networking");
/*
* 6 and 2 set as reasonable parameters for 3 or 4 nameserver
* systems.
*/
}
#define EDNSOPTS 100U
static unsigned char ednsoptscnt = 0;
typedef struct dig_ednsoptname {
const char *name;
dig_ednsoptname_t optnames[] = {
{ 3, "NSID" }, /* RFC 5001 */
{ 5, "DAU" }, /* RFC 6975 */
{ 6, "DHU" }, /* RFC 6975 */
{ 7, "N3U" }, /* RFC 6975 */
{ 8, "ECS" }, /* RFC 7871 */
{ 9, "EXPIRE" }, /* RFC 7314 */
{ 10, "COOKIE" }, /* RFC 7873 */
{ 11, "KEEPALIVE" }, /* RFC 7828 */
{ 12, "PADDING" }, /* RFC 7830 */
{ 12, "PAD" }, /* shorthand */
{ 13, "CHAIN" }, /* RFC 7901 */
{ 14, "KEY-TAG" }, /* RFC 8145 */
{ 26946, "DEVICEID" }, /* Brian Hartvigsen */
};
void
isc_buffer_t b;
unsigned int i;
if (ednsoptscnt == EDNSOPTS)
fatal("too many ednsopts");
for (i = 0; i < N_EDNS_OPTNAMES; i++) {
break;
}
}
if (!found) {
if (result != ISC_R_SUCCESS)
}
char *buf;
fatal("out of memory");
}
if (lookup->ednsoptscnt == 0)
lookup->ednsoptscnt++;
ednsoptscnt++;
}
/*%
* Add EDNS0 option record to a message. Currently, the only supported
* options are UDP buffer size, the DO bit, and EDNS options
* (e.g., NSID, COOKIE, client-subnet)
*/
static void
{
debug("add_opt()");
}
/*%
* Add a question section to a message, asking for the specified name,
* type, and class.
*/
static void
{
debug("add_question()");
}
/*%
* Check if we're done with all the queued lookups, which is true iff
* all sockets, sends, and recvs are accounted for (counters == 0),
* and the lookup list is empty.
* If we are done, pass control back out to dighost_shutdown() (which is
* part of dig.c, host.c, or nslookup.c) to either shutdown the system as
* a whole or reseed the lookup list.
*/
static void
check_if_done(void) {
debug("check_if_done()");
sendcount == 0) {
debug("shutting down");
}
}
/*%
* Clear out a query when we're done with it. WARNING: This routine
* WILL invalidate the query pointer.
*/
static void
link);
link);
sockcount--;
}
if (query->waiting_senddone)
else
}
/*%
* Try and clear out a lookup if we're done with it. Return ISC_TRUE if
* the lookup was successfully cleared. If ISC_TRUE is returned, the
* lookup pointer has been invalidated.
*/
static isc_boolean_t
dig_query_t *q;
{
if (debugging) {
q = ISC_LIST_HEAD(lookup->q);
while (q != NULL) {
q = ISC_LIST_NEXT(q, link);
}
while (q != NULL) {
debug("query to %s still connecting",
q->servname);
q = ISC_LIST_NEXT(q, clink);
}
}
return (ISC_FALSE);
}
/*
* At this point, we know there are no queries on the lookup,
* so can make it go away also.
*/
return (ISC_TRUE);
}
void
dig_server_t *s;
void *ptr;
debug("destroy");
while (s != NULL) {
ptr = s;
s = ISC_LIST_NEXT(s, link);
}
}
}
/*%
* If we can, start the next lookup in the queue running.
* This assumes that the lookup on the head of the queue hasn't been
* started yet. It also removes the lookup from the head of the queue,
* setting the current_lookup pointer pointing to it.
*/
void
start_lookup(void) {
debug("start_lookup()");
if (cancel_now)
return;
/*
* If there's a current lookup running, we really shouldn't get
* here.
*/
/*
* Put the current lookup somewhere so cancel_all can find it
*/
if (current_lookup != NULL) {
#if DIG_SIGCHASE_TD
if (current_lookup->do_topdown &&
isc_buffer_t *b = NULL;
isc_region_t r;
int i;
result = get_trusted_key();
if (result != ISC_R_SUCCESS) {
printf("\n;; No trusted key, "
"+sigchase option is disabled\n");
goto novalidation;
}
/*
* Verify temp is really the lowest
* WARNING
*/
}
printf("\n;; The queried zone: ");
printf(" isn't a subdomain of any Trusted Keys"
": +sigchase option is disable\n");
goto novalidation;
}
= current_lookup->rdtype;
ISC_FALSE, b);
isc_buffer_usedregion(b, &r);
MXNAME);
isc_buffer_free(&b);
&chase_name);
}
#endif
if (setup_lookup(current_lookup))
else if (next_origin(current_lookup))
} else {
}
}
/*%
* If we can, clear the current lookup and start the next one running.
* This calls try_clear_lookup, so may invalidate the lookup pointer.
*/
static void
debug("still have a worker");
return;
}
if (try_clear_lookup(lookup)) {
start_lookup();
}
}
/*%
* Create and queue a new lookup as a followup to the current lookup,
* based on the supplied message and section. This is used in trace and
* name server search modes to start a new lookup using servers from
* NS records in a reply. Returns the number of followup lookups made.
*/
static int
{
int numLookups = 0;
int num;
char bad_namestr[DNS_NAME_FORMATSIZE];
bad_namestr[0] = '\0';
result == ISC_R_SUCCESS;
if (section == DNS_SECTION_AUTHORITY) {
0, &rdataset);
if (result == ISC_R_SUCCESS)
return (0);
}
&rdataset);
if (result != ISC_R_SUCCESS)
continue;
debug("found NS set");
unsigned int nlabels;
int order;
if (namereln == dns_namereln_equal) {
if (!horizontal)
printf(";; BAD (HORIZONTAL) REFERRAL\n");
} else if (namereln != dns_namereln_subdomain) {
if (!bad)
printf(";; BAD REFERRAL\n");
continue;
}
}
result == ISC_R_SUCCESS;
char namestr[DNS_NAME_FORMATSIZE];
break;
/* Initialize lookup if we've not yet */
if (!success) {
if (!lookup->trace_root &&
else
if (lookup->ns_search_only)
}
if (lresult != ISC_R_SUCCESS) {
printf("couldn't get address for '%s': %s\n",
if (addresses_result == ISC_R_SUCCESS) {
sizeof(bad_namestr));
}
}
numLookups += num;
}
}
fatal("couldn't get address for '%s': %s",
}
section == DNS_SECTION_ANSWER &&
/*
* Randomize the order the nameserver will be tried.
*/
if (numLookups > 1) {
isc_uint32_t i, j;
i = numLookups;
INSIST(i > 0);
isc_random_get(&j);
j %= i;
}
i--;
}
}
return (numLookups);
}
/*%
* Create and queue a new lookup using the next origin from the search
* list, read in setup_system().
*
* Return ISC_TRUE iff there was another searchlist entry.
*/
static isc_boolean_t
debug("next_origin()");
if (!usesearch)
/*
* We're not using a search list, so don't even think
* about finding the next entry.
*/
return (ISC_FALSE);
/*
* Check for a absolute name or ndots being met.
*/
0, NULL);
if (result == ISC_R_SUCCESS &&
(dns_name_isabsolute(name) ||
return (ISC_FALSE);
/*
* Then we just did rootorg; there's nothing left.
*/
return (ISC_FALSE);
} else {
return (ISC_FALSE);
}
return (ISC_TRUE);
}
/*%
* Insert an SOA record into the sendmessage in a lookup. Used for
* creating IXFR queries.
*/
static void
debug("insert_soa()");
sizeof(lookup->rdatastore));
}
static void
/* XXXMPA need to fix, should be per server. */
}
/*%
* Setup the supplied lookup structure, making it ready to start sending
* queries to servers. Create and initialize the message to be sent as
* well as the query structures and buffer space for the replies. If the
* server list is empty, clone it from the system default list.
*/
unsigned int len;
isc_buffer_t b;
char ecsbuf[20];
char cookiebuf[256];
#ifdef WITH_IDN
#endif
#ifdef WITH_IDN
output_filter : NULL);
#endif
if (lookup->new_search) {
debug("resetting lookup counter.");
lookup_counter = 0;
}
debug("cloning server list");
}
sizeof(lookup->name_space));
sizeof(lookup->oname_space));
#ifdef WITH_IDN
/*
* We cannot convert `textname' and `origin' separately.
* `textname' doesn't contain TLD, but local mapping needs
* TLD.
*/
utf8_textname, sizeof(utf8_textname));
#endif
/*
* If the name has too many dots, force the origin to be NULL
* (which produces an absolute lookup). Otherwise, take the origin
* we have if there's one in the struct already. If it's NULL,
* take the first entry in the searchlist iff either usesearch
* is TRUE or we got a domain line in the resolv.conf file.
*/
if (lookup->new_search) {
#ifdef WITH_IDN
}
#else
}
#endif
}
#ifdef WITH_IDN
sizeof(utf8_origin));
sizeof(utf8_textname));
}
idn_textname, sizeof(idn_textname));
#else
/* XXX Helper funct to conv char* to name? */
isc_buffer_add(&b, len);
if (result != ISC_R_SUCCESS) {
fatal("'%s' is not in legal name syntax (%s)",
}
} else {
isc_buffer_add(&b, len);
if (result == ISC_R_SUCCESS &&
else if (result == ISC_R_SUCCESS)
if (result != ISC_R_SUCCESS) {
if (result == DNS_R_NAMETOOLONG)
return (ISC_FALSE);
fatal("'%s' is not in legal name syntax (%s)",
}
}
} else
#endif
{
debug("using root origin");
else {
#ifdef WITH_IDN
isc_buffer_add(&b, len);
dns_rootname, 0,
#else
isc_buffer_add(&b, len);
dns_rootname, 0,
#endif
}
if (result != ISC_R_SUCCESS) {
fatal("'%s' is not a legal name "
}
}
isc_random_get(&id);
lookup->msgcounter = 0;
/*
* If this is a trace request, completely disallow recursion, since
* it's meaningless for traces.
*/
debug("recursive query");
}
/* XXX aaflag */
debug("AA query");
}
debug("AD query");
}
debug("CD query");
}
debug("Z query");
}
}
/*
* Force TCP mode if we're doing an axfr.
*/
}
}
if (!lookup->header_only)
/* add_soa */
/* XXX Insist this? */
debug("initializing keys");
}
fatal("memory allocation failure");
debug("starting to render the message");
{
unsigned int flags;
int i = 0;
INSIST(i < DNS_EDNSOPTIONS);
i++;
}
struct sockaddr_in *sin;
struct sockaddr_in6 *sin6;
/* Round up prefix len to a multiple of 8 */
INSIST(i < DNS_EDNSOPTIONS);
/*
* XXXMUKS: According to RFC7871, "If there is
* no ADDRESS set, i.e., SOURCE PREFIX-LENGTH is
* set to 0, then FAMILY SHOULD be set to the
* transport over which the query is sent."
*
* However, at this point we don't know what
* transport(s) we'll be using, so we can't
* set the value now. For now, we're using
* IPv4 as the default the +subnet option
* used an IPv4 prefix, or for +subnet=0,
* and IPv6 if the +subnet option used an
* IPv6 prefix.
*
* (For future work: preserve the offset into
* the buffer where the family field is;
* that way we can update it in send_udp()
* or send_tcp_connect() once we know
* what it outght to be.)
*/
case AF_UNSPEC:
family = 1;
break;
case AF_INET:
family = 1;
break;
case AF_INET6:
family = 2;
break;
default:
INSIST(0);
}
/* family */
isc_buffer_putuint16(&b, family);
/* source prefix-length */
isc_buffer_putuint8(&b, plen);
/* scope prefix-length */
isc_buffer_putuint8(&b, 0);
/* address */
if (addrl > 0) {
/* Mask off last address byte */
if ((plen % 8) != 0)
isc_buffer_putmem(&b, addr,
(unsigned)addrl);
}
i++;
}
if (lookup->sendcookie) {
INSIST(i < DNS_EDNSOPTIONS);
isc_buffer_init(&b, cookiebuf,
sizeof(cookiebuf));
&b);
} else {
}
i++;
}
INSIST(i < DNS_EDNSOPTIONS);
i++;
}
if (lookup->ednsoptscnt != 0) {
i += lookup->ednsoptscnt;
}
}
DNS_SECTION_QUESTION, 0);
debug("done rendering");
/*
* Force TCP mode if the request is larger than 512 bytes.
*/
fatal("memory allocation failure in %s:%d",
debug("create query %p linked to lookup %p",
query->first_rr_serial = 0;
query->second_rr_serial = 0;
query->byte_count = 0;
fatal("memory allocation failure");
}
/* XXX qrflag, print_query, etc... */
extrabytes = 0;
ISC_TRUE);
printf(";; QUERY SIZE: %u\n\n",
}
return (ISC_TRUE);
}
/*%
* Event handler for send completion. Track send counter, and clear out
* the query if the send was canceled.
*/
static void
isc_buffer_t *b = NULL;
dig_lookup_t *l;
debug("send_done()");
sendcount--;
b != NULL;
isc_mem_free(mctx, b);
}
debug("sending next, since searching");
}
if (query->pending_free)
}
/*%
* Cancel a lookup, sending isc_socket_cancel() requests to all outstanding
* IO sockets. The cancel handlers should take care of cleaning up the
* query and lookup structures
*/
static void
debug("cancel_lookup()");
} else {
}
}
}
static void
dig_lookup_t *l;
unsigned int local_timeout;
debug("bringup_timer()");
/*
* If the timer already exists, that means we're calling this
* a second time (for a retry). Don't need to recreate it,
* just reset it.
*/
else {
if (timeout == 0)
else
}
}
static void
debug("force_timeout ()");
sizeof(isc_event_t));
fatal("isc_event_allocate: %s",
}
/*
* The timer may have expired if, for example, get_address() takes
* long time and the timer was running on a different thread.
* We need to cancel the possible timeout event not to confuse
* ourselves due to the duplicate events.
*/
}
static void
/*%
* Unlike send_udp, this can't be called multiple times with the same
* query. When we retry TCP, we requeue the whole lookup, which should
* start anew.
*/
static void
dig_lookup_t *l;
if (result != ISC_R_SUCCESS) {
/*
* This servname doesn't have an address. Try the next server
* by triggering an immediate 'timeout' (we lie, but the effect
* is the same).
*/
return;
}
char buf[ISC_NETADDR_FORMATSIZE];
else
printf(";; No acceptable nameservers\n");
return;
}
return;
}
if (specified_source &&
isc_sockaddr_pf(&bind_address))) {
printf(";; Skipping server %s, incompatible "
else
printf(";; No acceptable nameservers\n");
return;
}
return;
}
sockcount++;
goto search;
}
sockcount++;
if (specified_source)
else {
else
}
/*
* If we're at the endgame of a nameserver search, we need to
* immediately bring up all the queries. Do it here.
*/
if (l->ns_search_only && !l->trace_root) {
debug("sending next, since searching");
} else
}
}
static isc_buffer_t *
fatal("memory allocation failure in %s:%d",
return (buffer);
}
/*%
* Send a UDP packet to the remote nameserver, possible starting the
* recv action as well. Also make sure that the timer is running and
* is properly reset.
*/
static void
dig_lookup_t *l = NULL;
l->current_query = query;
/* XXX Check the sense of this, need assertion? */
if (result != ISC_R_SUCCESS) {
/* This servname doesn't have an address. */
return;
}
if (!l->mapped &&
char buf[ISC_NETADDR_FORMATSIZE];
printf(";; No acceptable nameservers\n");
return;
}
sockcount++;
if (specified_source) {
} else {
}
link);
debug("recving with lookup=%p, query=%p, sock=%p",
recvcount++;
}
debug("sending a request");
sendcount++;
}
/*%
* IO timeout handler, used for both connect and recv timeouts. If
* retries are still allowed, either resend the UDP packet or queue a
* new TCP lookup. Otherwise, cancel the lookup.
*/
static void
dig_lookup_t *l = NULL;
debug("connect_timeout()");
debug("trying next server...");
if (!l->tcp_mode)
else {
}
return;
}
}
if (l->retries > 1) {
if (!l->tcp_mode) {
l->retries--;
debug("resending UDP request to first server");
send_udp(ISC_LIST_HEAD(l->q));
} else {
debug("making new TCP request, %d tries left",
l->retries);
l->retries--;
requeue_lookup(l, ISC_TRUE);
cancel_lookup(l);
}
} else {
if (!l->ns_search_only) {
printf(";; connection timed out; no servers could be "
"reached\n");
}
cancel_lookup(l);
if (exitcode < 9)
exitcode = 9;
}
}
/*%
* Event handler for the TCP recv which gets the length header of TCP
* packets. Start the next recv of length bytes.
*/
static void
isc_buffer_t *b = NULL;
dig_lookup_t *l;
debug("tcp_length_done()");
recvcount--;
return;
}
char sockstr[ISC_SOCKADDR_FORMATSIZE];
sizeof(sockstr));
printf(";; communications error to %s: %s\n",
sockcount--;
return;
}
length = isc_buffer_getuint16(b);
if (length == 0) {
return;
}
/*
* Even though the buffer was already init'ed, we need
* to redo it now, to force the length we want.
*/
recvcount++;
debug("resubmitted recv request with length %d, recvcount=%d",
}
/*%
* For transfers that involve multiple recvs (XFR's in particular),
* launch the next recv.
*/
static void
dig_lookup_t *l;
debug("launch_next_query()");
debug("ignoring launch_next_query because !pending");
sockcount--;
return;
}
if (!query->first_soa_rcvd) {
if (include_question) {
}
}
recvcount++;
if (!query->first_soa_rcvd) {
debug("sending a request in launch_next_query");
sendcount++;
}
#if 0
#endif
return;
}
/*%
* Event handler for TCP connect complete. Make sure the connection was
* successful, then pass into launch_next_query to actually send the
* question.
*/
static void
char sockstr[ISC_SOCKADDR_FORMATSIZE];
dig_lookup_t *l;
debug("connect_done()");
debug("in cancel handler");
printf(";; Connection to %s(%s) for %s failed: %s.\n",
sockcount--;
return;
}
debug("unsuccessful connection: %s",
printf(";; Connection to %s(%s) for %s failed: "
"%s.\n", sockstr,
sockcount--;
/* XXX Clean up exitcodes */
if (exitcode < 9)
exitcode = 9;
if ((l->current_query != NULL) &&
else
} else
return;
}
if (keep_open) {
}
}
/*%
* Check if the ongoing XFR needs more data before it's complete, using
* the semantics of IXFR and AXFR protocols. Much of the complexity of
* this routine comes from determining when an IXFR is complete.
* ISC_FALSE means more data is on the way, and the recv has been issued.
*/
static isc_boolean_t
{
if (ixfr)
debug("check_for_more_data()");
/*
* By the time we're in this routine, we know we're doing
* either an AXFR or IXFR. If there's no second_rr_type,
* then we don't yet know which kind of answer we got back
* from the server. Here, we're going to walk through the
* rr's in the message, acting as necessary whenever we hit
* an SOA rr.
*/
if (result != ISC_R_SUCCESS) {
puts("; Transfer failed.");
return (ISC_TRUE);
}
do {
&name);
if (result != ISC_R_SUCCESS)
continue;
do {
/*
* If this is the first rr, make sure
* it's an SOA
*/
if ((!query->first_soa_rcvd) &&
puts("; Transfer failed. "
"Didn't start with SOA answer.");
return (ISC_TRUE);
}
if ((!query->second_rr_rcvd) &&
query->second_rr_serial = 0;
debug("got the second rr as nonsoa");
goto next_rdata;
}
/*
* If the record is anything except an SOA
* now, just continue on...
*/
goto next_rdata;
/* Now we have an SOA. Work with it. */
debug("got an SOA");
if (!query->first_soa_rcvd) {
debug("this is the first serial %u",
serial);
serial)) {
debug("got up to date "
"response");
goto doexit;
}
goto next_rdata;
}
if (axfr) {
debug("doing axfr, got second SOA");
goto doexit;
}
if (!query->second_rr_rcvd) {
debug("doing ixfr, got "
"empty zone");
goto doexit;
}
debug("this is the second serial %u",
serial);
goto next_rdata;
}
/*
* If we get to this point, we're doing an
* IXFR and have to start really looking
* at serial numbers.
*/
debug("got a match for ixfr");
if (!query->first_repeat_rcvd) {
goto next_rdata;
}
debug("done with ixfr");
goto doexit;
}
} while (result == ISC_R_SUCCESS);
}
} while (result == ISC_R_SUCCESS);
return (ISC_FALSE);
return (ISC_TRUE);
}
static void
{
char bb[256];
const unsigned char *sent;
} else {
}
} else {
printf(";; Warning: Client COOKIE mismatch\n");
}
} else {
printf(";; Warning: COOKIE bad token (too short)\n");
}
if (copy) {
isc_region_t r;
if (isc_buffer_availablelength(&hexbuf) > 0) {
isc_buffer_putuint8(&hexbuf, 0);
l->cookie = servercookie;
}
}
}
static void
if (result == ISC_R_SUCCESS) {
switch (optcode) {
case DNS_OPT_COOKIE:
/*
* Only process the first cookie option.
*/
if (seen_cookie) {
break;
}
break;
default:
break;
}
}
}
}
static int
}
/*%
* Event handler for recv complete. Perform whatever actions are necessary,
* based on the specifics of the user's request.
*/
static void
isc_buffer_t *b = NULL;
#ifdef DIG_SIGCHASE
#endif
dig_lookup_t *n, *l;
unsigned int parseflags;
unsigned int msgflags;
#ifdef DIG_SIGCHASE
isc_region_t r;
#endif
int newedns;
debug("recv_done()");
recvcount--;
debug("no longer pending. Got %s",
return;
}
debug("in recv cancel handler");
} else {
printf(";; communications error: %s\n",
sockcount--;
}
return;
}
if (!l->tcp_mode &&
char buf1[ISC_SOCKADDR_FORMATSIZE];
char buf2[ISC_SOCKADDR_FORMATSIZE];
else
/*
* We don't expect a match when the packet is
* sent to 0.0.0.0, :: or to a multicast addresses.
* XXXMPA broadcast needs to be handled here as well.
*/
sizeof(buf1));
sizeof(buf2));
printf(";; reply from unexpected source: %s,"
}
}
if (l->tcp_mode) {
if (result == ISC_R_SUCCESS) {
if (!query->first_soa_rcvd ||
printf(";; %s: ID mismatch: "
"expected ID %u, got %u\n",
"WARNING" : "ERROR",
if (query->first_soa_rcvd)
} else
printf(";; ERROR: short "
"(< header size) message\n");
if (fail) {
return;
}
} else if (result == ISC_R_SUCCESS)
printf(";; Warning: ID mismatch: "
else
printf(";; Warning: short "
"(< header size) message received\n");
}
printf(";; Warning: query response not set\n");
if (!match)
goto udp_mismatch;
debug("getting initial querysig");
&l->querysig);
}
if (l->msgcounter != 0)
l->msgcounter++;
}
debug("before parse starts");
#ifdef DIG_SIGCHASE
if (!l->sigchase) {
} else {
parseflags = 0;
}
#endif
if (l->besteffort) {
}
if (result == DNS_R_RECOVERABLE) {
printf(";; Warning: Message parser reports malformed "
"message packet.\n");
}
if (result != ISC_R_SUCCESS) {
hex_dump(b);
cancel_lookup(l);
return;
}
&name);
char namestr[DNS_NAME_FORMATSIZE];
char typebuf[DNS_RDATATYPE_FORMATSIZE];
sizeof(namestr));
sizeof(typebuf));
sizeof(classbuf));
printf(";; Question section mismatch: "
"got %s/%s/%s\n",
}
}
}
if (!match) {
if (l->tcp_mode) {
return;
} else
goto udp_mismatch;
}
}
/*
* Add minimum EDNS version required checks here if needed.
*/
if (l->comments)
printf(";; BADVERS, retrying with EDNS version %u.\n",
newedns);
n = requeue_lookup(l, ISC_TRUE);
if (l->trace && l->trace_root)
cancel_lookup(l);
return;
}
process_opt(l, msg);
if (l->comments)
printf(";; Truncated, retrying in TCP mode.\n");
n = requeue_lookup(l, ISC_TRUE);
if (l->trace && l->trace_root)
cancel_lookup(l);
return;
}
l->sendcookie && l->badcookie) {
process_opt(l, msg);
if (l->comments)
printf(";; BADCOOKIE, retrying%s.\n",
n = requeue_lookup(l, ISC_TRUE);
if (l->seenbadcookie)
n->seenbadcookie = ISC_TRUE;
if (l->trace && l->trace_root)
cancel_lookup(l);
return;
}
}
{
if (l->current_query == query)
l->current_query = NULL;
if (l->tcp_mode)
else
}
/*
* If our query is at the head of the list and there
* is no next, we're the only one left, so fall
* through to print the message.
*/
if ((ISC_LIST_HEAD(l->q) != query) ||
if (l->comments)
printf(";; Got %s from %s, "
"trying next server\n",
"SERVFAIL reply" :
"recursion not available",
return;
}
}
if (result != ISC_R_SUCCESS) {
printf(";; Couldn't verify signature: %s\n",
}
isc_buffer_free(&l->querysig);
}
}
debug("after parse");
/*
* Once we are in the XFR message, increase
* the timeout to much longer, so brief network
* outages won't cause the XFR to abort
*/
unsigned int local_timeout;
if (timeout == 0) {
if (l->tcp_mode)
else
} else {
else
}
NULL,
&l->interval,
}
}
printf(";; expected opt record in response\n");
else
process_opt(l, msg);
process_opt(l, msg);
}
} else if (!l->trace && !l->ns_search_only) {
#ifdef DIG_SIGCHASE
if (!do_sigchase)
#endif
} else if (l->trace) {
int nl = 0;
debug("in TRACE code");
if (!l->ns_search_only)
if (!l->trace_root)
l->rdtype = dns_rdatatype_soa;
l->trace_root = ISC_FALSE;
} else if (count == 0)
if (nl == 0)
} else {
debug("in NSSEARCH code");
if (l->trace_root) {
/*
* This is the initial NS query.
*/
int nl;
l->rdtype = dns_rdatatype_soa;
if (nl == 0)
l->trace_root = ISC_FALSE;
} else
#ifdef DIG_SIGCHASE
if (!do_sigchase)
#endif
}
#ifdef DIG_SIGCHASE
if (do_sigchase) {
sizeof(dig_message_t));
fatal("Memory allocation failure in %s:%d",
}
link);
&msg_temp) != ISC_R_SUCCESS) {
fatal("dns_message_create in %s:%d",
}
isc_buffer_usedregion(b, &r);
sizeof(dig_message_t));
if (chase_msg2 == NULL) {
fatal("Memory allocation failure in %s:%d",
}
link);
}
#endif
}
#ifdef DIG_SIGCHASE
}
#endif
if (l->pending)
debug("still pending.");
if (l->doing_xfr) {
return;
}
if (!docancel)
if (docancel) {
cancel_lookup(l);
}
} else {
#ifdef DIG_SIGCHASE
if (!l->sigchase)
#endif
}
#ifdef DIG_SIGCHASE
if (!do_sigchase)
#endif
cancel_lookup(l);
}
}
#ifdef DIG_SIGCHASE
if (do_sigchase)
else
#endif
}
return;
recvcount++;
return;
}
/*%
* Turn a name into an address, using system-supplied routines. This is
* used in looking up server names, etc... and needs to use system-supplied
* routines, since they may be using a non-DNS system for these lookups.
*/
int count;
if (is_running)
if (is_running)
if (result != ISC_R_SUCCESS)
return (result);
return (ISC_R_SUCCESS);
}
int
int count, i;
char tmp[ISC_NETADDR_FORMATSIZE];
if (result != ISC_R_SUCCESS) {
fatal("couldn't get address for '%s': %s",
return (0);
}
for (i = 0; i < count; i++) {
}
return (count);
}
/*%
* Initiate either a TCP or UDP lookup
*/
void
debug("do_lookup()");
else
}
}
/*%
* Start everything in action upon task startup.
*/
void
start_lookup();
}
/*%
* Make everything on the lookup queue go away. Mainly used by the
* SIGINT handler.
*/
void
cancel_all(void) {
dig_lookup_t *l, *n;
dig_query_t *q, *nq;
debug("cancel_all()");
if (free_now) {
return;
}
if (current_lookup != NULL) {
for (q = ISC_LIST_HEAD(current_lookup->q);
q != NULL;
q = nq)
{
debug("canceling pending query %p, belonging to %p",
q, current_lookup);
else
clear_query(q);
}
q != NULL;
q = nq)
{
debug("canceling connecting query %p, belonging to %p",
q, current_lookup);
else
clear_query(q);
}
}
l = ISC_LIST_HEAD(lookup_list);
while (l != NULL) {
n = ISC_LIST_NEXT(l, link);
try_clear_lookup(l);
l = n;
}
}
/*%
* Destroy all of the libs we are using, and get everything ready for a
* clean shutdown.
*/
void
destroy_libs(void) {
#ifdef DIG_SIGCHASE
void * ptr;
#endif
#ifdef WITH_IDN
#endif
debug("destroy_libs()");
if (global_task != NULL) {
debug("freeing task");
}
/*
* The taskmgr_destroy() call blocks until all events are cleared
* from the task.
*/
debug("freeing taskmgr");
}
#ifdef WITH_IDN
#endif
debug("freeing commctx");
}
debug("freeing socketmgr");
}
debug("freeing timermgr");
}
}
if (is_dst_up) {
debug("destroy DST lib");
}
debug("detach from entropy");
}
#ifdef DIG_SIGCHASE
debug("Destroy the messages kept for sigchase");
/* Destroy the messages kept for sigchase */
}
}
if (dns_name_dynamic(&chase_name))
#if DIG_SIGCHASE_TD
#endif
#if DIG_SIGCHASE_BU
if (dns_name_dynamic(&chase_signame))
#endif
#endif
debug("Removing log context");
while (ednsoptscnt > 0U) {
ednsoptscnt--;
}
debug("Destroy memory");
if (memdebugging != 0)
}
#ifdef WITH_IDN
static void
initialize_idn(void) {
idn_result_t r;
#ifdef HAVE_SETLOCALE
/* Set locale */
#endif
/* Create configuration context. */
r = idn_nameinit(1);
if (r != idn_success)
fatal("idn api initialization failed: %s",
idn_result_tostring(r));
/* Set domain name -> text post-conversion filter. */
}
static isc_result_t
{
/*
* Copy contents of 'buffer' to 'tmp1', supply trailing dot
* if 'absolute' is true, and terminate with NUL.
*/
return (ISC_R_SUCCESS);
if (absolute && !end_with_dot) {
fromlen++;
return (ISC_R_SUCCESS);
}
/*
* Convert contents of 'tmp1' to local encoding.
*/
return (ISC_R_SUCCESS);
/*
* Copy the converted contents in 'tmp1' back to 'buffer'.
* If we have appended trailing dot, remove it.
*/
tolen--;
return (ISC_R_NOSPACE);
return (ISC_R_SUCCESS);
}
static idn_result_t
/* Already absolute? */
return (idn_success);
/* Append dot and origin */
return (idn_buffer_overflow);
if (*origin != '.')
return (idn_success);
}
static void
if (r != idn_success) {
exitcode = 1;
}
}
#endif /* WITH_IDN */
#ifdef DIG_SIGCHASE
void
{
isc_buffer_t * b = NULL;
isc_region_t r;
isc_buffer_usedregion(b, &r);
isc_buffer_free(&b);
}
void
{
do {
printf("\n");
printf("end\n");
}
}
void
dump_database(void) {
dig_message_t * msg;
== ISC_R_SUCCESS)
== ISC_R_SUCCESS)
== ISC_R_SUCCESS)
}
}
if (type == dns_rdatatype_any) {
return (rdataset);
} else if ((type == dns_rdatatype_rrsig) &&
(covers == dns_rdatatype_any)) {
return (rdataset);
}
return (rdataset);
}
return (NULL);
}
int section)
{
return (NULL);
do {
return (rdataset);
}
return (NULL);
}
{
dig_message_t * msg;
== ISC_R_SUCCESS)
{
return (rdataset);
}
== ISC_R_SUCCESS)
{
rdataset =
return (rdataset);
}
== ISC_R_SUCCESS)
{
rdataset =
return (rdataset);
}
}
return (NULL);
}
{
isc_buffer_t *b = NULL;
isc_region_t r;
return (temp);
return (NULL);
isc_buffer_usedregion(b, &r);
isc_buffer_free(&b);
if (type == dns_rdatatype_rrsig)
else
return (NULL);
}
printf("\n\nLaunch a query to find a RRset of type ");
return (NULL);
}
{
return (ISC_R_SUCCESS);
result == ISC_R_SUCCESS;
isc_buffer_t b;
return (ISC_R_SUCCESS);
if (result != ISC_R_SUCCESS)
continue;
}
return (ISC_R_SUCCESS);
}
void
{
int i = 0;
for (i= 0; i < MAX_TRUSTED_KEY; i++) {
} else
break;
}
return;
}
char alphnum[] =
"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789";
removetmpkey(const char *file)
{
char *tempnamekey = NULL;
int tempnamekeylen;
if (tempnamekey == NULL)
return (ISC_R_NOMEMORY);
return (result);
}
get_trusted_key(void) {
return (ISC_R_FAILURE);
else
filename = "./trusted-key.key";
} else
filename = "/etc/trusted-key.key";
} else
printf("No trusted key\n");
return (ISC_R_FAILURE);
}
}
static void
if (dns_name_dynamic(p_ret))
}
#if DIG_SIGCHASE_TD
{
dig_server_t *s;
void *ptr;
while (s != NULL) {
debug("freeing server %p belonging to %p",
s, lookup);
ptr = s;
s = ISC_LIST_NEXT(s, link);
}
result == ISC_R_SUCCESS;
char namestr[DNS_NAME_FORMATSIZE];
#define __FOLLOW_GLUE__
#ifdef __FOLLOW_GLUE__
isc_buffer_t *b = NULL;
isc_region_t r;
isc_boolean_t true = ISC_TRUE;
#endif
#ifdef __FOLLOW_GLUE__
dns_rdatatype_any, &true);
if (result == ISC_R_SUCCESS) {
result == ISC_R_SUCCESS;
isc_buffer_usedregion(b, &r);
isc_buffer_free(&b);
}
}
dns_rdatatype_any, &true);
if (result == ISC_R_SUCCESS) {
result == ISC_R_SUCCESS;
dns_rdataset_current(rdataset, &a);
isc_buffer_usedregion(b, &r);
isc_buffer_free(&b);
dns_rdata_reset(&a);
}
}
#else
printf("ns name: ");
printf("\n");
#endif
}
printf("\nLaunch a query to find a RRset of type ");
printf(" with nameservers:");
printf("\n");
return (ISC_R_SUCCESS);
}
{
int orderp;
unsigned int nlabelsp;
if (name_reln != dns_namereln_subdomain ||
printf("\n;; ERROR : ");
printf(" is not a subdomain of: ");
printf(" FAILED\n\n");
return (ISC_R_FAILURE);
}
return (ISC_R_SUCCESS);
}
do {
goto cleanup;
}
return (result);
}
{
isc_boolean_t true = ISC_TRUE;
dns_rdatatype_any, &true);
if (result != ISC_R_SUCCESS) {
printf("\n;; NS RRset is missing to continue validation:"
" FAILED\n\n");
return (ISC_R_FAILURE);
}
return (ISC_R_SUCCESS);
}
#endif
void
{
isc_buffer_t *b = NULL;
isc_region_t r;
isc_buffer_usedregion(b, &r);
isc_buffer_free(&b);
}
void
if (dns_name_dynamic(target))
}
void
}
/*
*
* take a DNSKEY RRset and the RRSIG RRset corresponding in parameter
* return ISC_R_SUCCESS if the DNSKEY RRset contains a trusted_key
* and the RRset is valid
* return ISC_R_NOTFOUND if not contains trusted key
or if the RRset isn't valid
* return ISC_R_FAILURE if problem
*
*/
{
int i;
return (ISC_R_FAILURE);
do {
== ISC_TRUE) {
printf(";; Ok, find a Trusted Key in the "
"DNSKEY RRset: %d\n",
if (result == ISC_R_SUCCESS)
goto cleanup;
}
}
return (result);
}
{
do {
if (result == ISC_R_SUCCESS)
goto cleanup;
return (result);
}
{
do {
/*
* Test if the id of the DNSKEY is
* the id of the DNSKEY signer's
*/
printf(";; VERIFYING ");
printf(" RRset for ");
if (result == ISC_R_SUCCESS)
goto cleanup;
}
return (result);
}
{
unsigned char dsbuf[DNS_DS_BUFFERSIZE];
do {
do {
/*
* Test if the id of the DNSKEY is the
* id of DNSKEY referenced by the DS
*/
dsbuf, &newdsrdata);
if (result != ISC_R_SUCCESS) {
printf("Oops: impossible to build"
" new DS rdata\n");
goto cleanup;
}
if (dns_rdata_compare(&dsrdata,
&newdsrdata) == 0) {
printf(";; OK a DS valids a DNSKEY"
" in the RRset\n");
printf(";; Now verify that this"
" DNSKEY validates the "
"DNSKEY RRset\n");
if (result == ISC_R_SUCCESS)
goto cleanup;
} else {
printf(";; This DS is NOT the DS for"
" the chasing KEY: FAILED\n");
}
}
return (result);
}
/*
*
* take a pointer on a rdataset in parameter and try to resolv it.
* the searched rrset is a rrset on 'name' with type 'type'
* (and if the type is a rrsig the signature cover 'covers').
* the lookedup is to known if you have already done the query on the net.
* ISC_R_SUCCESS: if we found the rrset
* ISC_R_NOTFOUND: we do not found the rrset in cache
* and we do a query on the net
* ISC_R_FAILURE: rrset not found
*/
{
return (ISC_R_SUCCESS);
tmplookedup = *lookedup;
if (tmplookedup)
return (ISC_R_FAILURE);
return (ISC_R_NOTFOUND);
}
return (ISC_R_SUCCESS);
}
#if DIG_SIGCHASE_TD
void
{
isc_boolean_t true = ISC_TRUE;
char buf[20];
isc_buffer_t b;
printf("error response code %.*s\n",
(int)isc_buffer_usedlength(&b), buf);
error_message = msg;
return;
}
== ISC_R_SUCCESS) {
if (current_lookup->trace_root_sigchase) {
return;
}
have_answer = true;
} else {
if (!current_lookup->trace_root_sigchase) {
if (result != ISC_R_SUCCESS) {
printf("no answer or authority section\n");
error_message = msg;
return;
}
&name);
if (chase_nsrdataset != NULL) {
printf("no response but there is a delegation"
" in authority section: ");
printf("\n");
} else {
printf("no response and no delegation in "
"authority section but a reference"
" to: ");
printf("\n");
error_message = msg;
}
} else {
printf(";; NO ANSWERS: %s\n",
return;
}
}
if (have_answer) {
if (chase_rdataset != NULL)
}
if (result == ISC_R_FAILURE) {
printf("\n;; DNSKEY is missing to continue validation:"
" FAILED\n\n");
goto cleanandgo;
}
if (result == ISC_R_NOTFOUND)
return;
printf("\n;; DNSKEYset:\n");
if (result == ISC_R_FAILURE) {
printf("\n;; RRSIG of DNSKEY is missing to continue validation:"
" FAILED\n\n");
goto cleanandgo;
}
if (result == ISC_R_NOTFOUND)
return;
printf("\n;; RRSIG of the DNSKEYset:\n");
if (!chase_dslookedup && !chase_nslookedup) {
if (!delegation_follow) {
} else {
}
if (result != ISC_R_SUCCESS) {
printf("\n;; chain of trust can't be validated:"
" FAILED\n\n");
goto cleanandgo;
} else {
}
}
/* test if it's a grand father case */
if (have_response) {
&true);
if (result == ISC_R_FAILURE) {
printf("\n;; RRset is missing to continue"
" validation SHOULD NOT APPEND:"
" FAILED\n\n");
goto cleanandgo;
}
} else {
&true);
if (result == ISC_R_FAILURE) {
printf("\n;; RRSIG is missing to continue"
" validation SHOULD NOT APPEND:"
" FAILED\n\n");
goto cleanandgo;
}
}
if (result != ISC_R_SUCCESS) {
printf("\n;; We are in a Grand Father Problem:"
" See 2.2.1 in RFC 3658\n");
&tmp_name);
printf(";; and we try to continue chain of trust"
" validation of the zone: ");
printf("\n");
} else {
if (have_response)
goto finalstep;
else
}
}
if (have_delegation_ns) {
if (result == ISC_R_FAILURE) {
printf("\n;;NSset is missing to continue validation:"
" FAILED\n\n");
goto cleanandgo;
}
if (result == ISC_R_NOTFOUND) {
return;
}
if (result == ISC_R_FAILURE) {
printf("\n;; DSset is missing to continue validation:"
" FAILED\n\n");
goto cleanandgo;
}
if (result == ISC_R_NOTFOUND)
return;
printf("\n;; DSset:\n");
&true);
if (result != ISC_R_SUCCESS) {
printf("\n;; DSset is missing to continue validation:"
" FAILED\n\n");
goto cleanandgo;
}
printf("\n;; RRSIGset of DSset\n");
if (result != ISC_R_SUCCESS) {
printf("\n;; Impossible to verify the DSset:"
" FAILED\n\n");
goto cleanandgo;
}
return;
}
if (error_message != NULL) {
&rdataset, &sigrdataset);
dns_name_countlabels(&rdata_name) == 0) {
printf("\n;; Impossible to verify the non-existence,"
" the NSEC RRset can't be validated:"
" FAILED\n\n");
goto cleanandgo;
}
if (ret != ISC_R_SUCCESS) {
printf("\n;; Impossible to verify the NSEC RR to prove"
" the non-existence : FAILED\n\n");
goto cleanandgo;
}
if (result != ISC_R_SUCCESS) {
printf("\n;; Impossible to verify the non-existence:"
" FAILED\n\n");
goto cleanandgo;
} else {
printf("\n;; OK the query doesn't have response but"
" we have validate this fact : SUCCESS\n\n");
goto cleanandgo;
}
}
printf(";; cleanandgo \n");
return;
&true);
if (result == ISC_R_FAILURE) {
printf("\n;; RRsig of RRset is missing to continue validation"
" SHOULD NOT APPEND: FAILED\n\n");
goto cleanandgo;
}
if (result != ISC_R_SUCCESS) {
printf("\n;; Impossible to verify the RRset : FAILED\n\n");
/*
printf("RRset:\n");
print_rdataset(&chase_name , chase_rdataset);
printf("DNSKEYset:\n");
print_rdataset(&chase_name , chase_keyrdataset);
printf("RRSIG of RRset:\n");
print_rdataset(&chase_name , chase_sigrdataset);
printf("\n");
*/
goto cleanandgo;
} else {
printf("\n;; The Answer:\n");
printf("\n;; FINISH : we have validate the DNSSEC chain"
" of trust: SUCCESS\n\n");
goto cleanandgo;
}
}
#endif
#if DIG_SIGCHASE_BU
{
isc_boolean_t true = ISC_TRUE;
!= ISC_R_SUCCESS) {
return (ISC_R_ADDRNOTAVAIL);
} else {
}
/* What do we chase? */
if (chase_rdataset == NULL) {
dns_rdatatype_any, &true);
if (result != ISC_R_SUCCESS) {
printf("\n;; No Answers: Validation FAILED\n\n");
return (ISC_R_NOTFOUND);
}
printf(";; RRset to chase:\n");
}
if (chase_sigrdataset == NULL) {
if (result == ISC_R_FAILURE) {
printf("\n;; RRSIG is missing for continue validation:"
" FAILED\n\n");
if (dns_name_dynamic(&chase_name))
return (ISC_R_NOTFOUND);
}
if (result == ISC_R_NOTFOUND) {
return (ISC_R_NOTFOUND);
}
printf("\n;; RRSIG of the RRset to chase:\n");
}
/* first find the DNSKEY name */
/* Do we have a key? */
if (chase_keyrdataset == NULL) {
if (result == ISC_R_FAILURE) {
printf("\n;; DNSKEY is missing to continue validation:"
" FAILED\n\n");
if (dns_name_dynamic(&chase_name))
return (ISC_R_NOTFOUND);
}
if (result == ISC_R_NOTFOUND) {
return (ISC_R_NOTFOUND);
}
printf("\n;; DNSKEYset that signs the RRset to chase:\n");
}
if (chase_sigkeyrdataset == NULL) {
if (result == ISC_R_FAILURE) {
printf("\n;; RRSIG for DNSKEY is missing to continue"
" validation : FAILED\n\n");
if (dns_name_dynamic(&chase_name))
return (ISC_R_NOTFOUND);
}
if (result == ISC_R_NOTFOUND) {
return (ISC_R_NOTFOUND);
}
printf("\n;; RRSIG of the DNSKEYset that signs the "
"RRset to chase:\n");
}
if (chase_dsrdataset == NULL) {
if (result == ISC_R_FAILURE) {
printf("\n;; WARNING There is no DS for the zone: ");
printf("\n");
}
if (result == ISC_R_NOTFOUND) {
return (ISC_R_NOTFOUND);
}
if (chase_dsrdataset != NULL) {
printf("\n;; DSset of the DNSKEYset\n");
}
}
if (chase_dsrdataset != NULL) {
/*
* if there is no RRSIG of DS,
* we don't want to search on the network
*/
dns_rdatatype_ds, &true);
if (result == ISC_R_FAILURE) {
printf(";; WARNING : NO RRSIG DS : RRSIG DS"
" should come with DS\n");
/*
* We continue even the DS couldn't be validated,
* because the DNSKEY could be a Trusted Key.
*/
} else {
printf("\n;; RRSIG of the DSset of the DNSKEYset\n");
}
}
return (1);
}
void
{
int ret;
result = get_trusted_key();
if (result != ISC_R_SUCCESS) {
printf("No trusted keys present\n");
return;
}
}
if (ret == ISC_R_NOTFOUND)
return;
if (ret == ISC_R_ADDRNOTAVAIL) {
/* We have no response */
&rdataset, &sigrdataset);
dns_name_countlabels(&rdata_name) == 0) {
printf("\n;; Impossible to verify the Non-existence,"
" the NSEC RRset can't be validated: "
"FAILED\n\n");
return;
}
if (result != ISC_R_SUCCESS) {
printf("\n No Answers and impossible to prove the"
" unsecurity : Validation FAILED\n\n");
return;
}
printf(";; An NSEC prove the non-existence of a answers,"
" Now we want validate this NSEC\n");
return;
}
printf("\n\n\n;; WE HAVE MATERIAL, WE NOW DO VALIDATION\n");
if (result != ISC_R_SUCCESS) {
printf(";; No DNSKEY is valid to check the RRSIG"
" of the RRset: FAILED\n");
return;
}
printf(";; OK We found DNSKEY (or more) to validate the RRset\n");
if (result == ISC_R_SUCCESS) {
printf("\n;; Ok this DNSKEY is a Trusted Key,"
" DNSSEC validation is ok: SUCCESS\n\n");
return;
}
printf(";; Now, we are going to validate this DNSKEY by the DS\n");
if (chase_dsrdataset == NULL) {
printf(";; the DNSKEY isn't trusted-key and there isn't"
" DS to validate the DNSKEY: FAILED\n");
return;
}
if (result != ISC_R_SUCCESS) {
printf(";; ERROR no DS validates a DNSKEY in the"
" DNSKEY RRset: FAILED\n");
return;
} else
printf(";; OK this DNSKEY (validated by the DS) validates"
" the RRset of the DNSKEYs, thus the DNSKEY validates"
" the RRset\n");
printf(";; Now, we want to validate the DS : recursive call\n");
return;
}
#endif
void
#if DIG_SIGCHASE_TD
if (current_lookup->do_topdown) {
return;
}
#endif
#if DIG_SIGCHASE_BU
return;
#endif
}
/*
* return 1 if name1 < name2
* 0 if name1 == name2
* -1 if name1 > name2
* and -2 if problem
*/
int
{
unsigned int nblabel1;
unsigned int nblabel2;
int min_lum_label;
int i;
int ret = -2;
else
for (i=1 ; i < min_lum_label; i++) {
if (ret < 0)
return (-1);
else if (ret > 0)
return (1);
}
}
return (0);
return (-1);
else
return (1);
}
/**
*
*
*
*/
{
!= ISC_R_SUCCESS) {
printf(";; nothing in authority section : impossible to"
" validate the non-existence : FAILED\n");
return (ISC_R_FAILURE);
}
do {
continue;
printf("There is a NSEC for this zone in the"
" AUTHORITY section:\n");
result == ISC_R_SUCCESS;
if (signsecset == NULL) {
printf(";; no RRSIG NSEC in authority section:"
" impossible to validate the "
"non-existence: FAILED\n");
return (ISC_R_FAILURE);
}
return (ISC_R_SUCCESS);
}
}
== ISC_R_SUCCESS);
*sigrdataset = NULL;
rdata_name = NULL;
return (ISC_R_FAILURE);
}
/**
*
*
*
*
*
*/
{
if (ret == ISC_R_SUCCESS)
printf("OK the NSEC said that the type doesn't exist \n");
if (signsecset == NULL) {
printf("There isn't RRSIG NSEC for the zone \n");
return (ISC_R_FAILURE);
}
return (ret);
}
/**
*
*
*
*
*/
{
printf("We want to prove the non-existence of a type of rdata %d"
" or of the zone: \n", type);
!= ISC_R_SUCCESS) {
printf(";; nothing in authority section : impossible to"
" validate the non-existence : FAILED\n");
return (ISC_R_FAILURE);
}
printf("We have a NSEC for this zone :OK\n");
if (ret != ISC_R_SUCCESS) {
printf("prove_nx: ERROR type exist\n");
return (ret);
} else {
printf("prove_nx: OK type does not exist\n");
return (ISC_R_SUCCESS);
}
} else {
printf("there is no NSEC for this zone: validating "
"that the zone doesn't exist\n");
return (ret);
}
/* Never get here */
}
#endif