dighost.c revision 46e349e515e0b992ecafdc9597f9d5ee0cf81b2a
/*
* Copyright (C) 2000, 2001 Internet Software Consortium.
*
* Permission to use, copy, modify, and distribute this software for any
* 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 INTERNET SOFTWARE CONSORTIUM
* DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL
* INTERNET SOFTWARE CONSORTIUM 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: dighost.c,v 1.212 2001/07/27 05:41:43 bwelling Exp $ */
/*
* 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>
#include <dns/fixedname.h>
#ifdef DNS_OPT_NEWCODES
#endif /* DNS_OPT_NEWCODES */
#include <dns/rdataclass.h>
#include <dns/rdatalist.h>
#include <dns/rdataset.h>
#include <dns/rdatastruct.h>
#include <dns/rdatatype.h>
#ifdef HAVE_ADDRINFO
#ifdef HAVE_GETADDRINFO
#ifdef HAVE_GAISTRERROR
#define USE_GETADDRINFO
#endif
#endif
#endif
#ifndef USE_GETADDRINFO
#ifndef ISC_PLATFORM_NONSTDHERRNO
extern int h_errno;
#endif
#endif
unsigned int timeout = 0;
int sendcount = 0;
int recvcount = 0;
int sockcount = 0;
int ndots = -1;
int tries = 2;
int lookup_counter = 0;
/*
* Exit Codes:
* 0 Everything went well, including things like NXDOMAIN
* 1 Usage error
* 7 Got too many RR's or Names
* 8 Couldn't open batch file
* 9 No reply from server
* 10 Internal error
*/
int exitcode = 0;
char keynametext[MXNAME];
/*
* 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");\
}
static void
static void
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;
isc_region_t r;
isc_buffer_usedregion(b, &r);
printf("\n");
}
if (len % 16 != 0)
printf("\n");
}
int adrs[4];
int remaining;
int i, n;
reverse[0] = 0;
if (n == 0) {
return (DNS_R_BADDOTTEDQUAD);
}
for (i = n - 1; i >= 0; i--) {
adrs[i]);
}
if (n <= 0)
return (DNS_R_BADDOTTEDQUAD);
if (result != ISC_R_SUCCESS)
return (result);
}
return (result);
}
void
if (exitcode < 10)
exitcode = 10;
}
void
if (debugging) {
}
}
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
*/
make_server(const char *servname) {
fatal("Memory allocation failure in %s:%d",
return (srv);
}
/*
* 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",
#ifdef DNS_OPT_NEWCODES_LIVE
#endif /* DNS_OPT_NEWCODES_LIVE */
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 seperately from somewhere else, or construct it by hand.
*/
debug("clone_lookup()");
looknew = make_empty_lookup();
#ifdef DNS_OPT_NEWCODES_LIVE
#endif /* DNS_OPT_NEWCODES_LIVE */
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);
}
static void
setup_text_key(void) {
int secretsize;
unsigned char *secretstore;
debug("setup_text_key()");
if (secretstore == NULL)
fatal("Memory allocation failure in %s:%d",
if (result != ISC_R_SUCCESS) {
printf(";; Couldn't create key %s: %s\n",
goto failure;
}
namebuf);
if (result != ISC_R_SUCCESS) {
printf(";; Couldn't create key %s: %s\n",
goto failure;
}
if (result != ISC_R_SUCCESS) {
printf(";; Couldn't create key %s: %s\n",
}
}
static void
setup_file_key(void) {
unsigned char *secretstore = NULL;
int secretlen;
debug("setup_file_key()");
if (result != ISC_R_SUCCESS) {
goto failure;
}
/*
* Get key size in bits, convert to bytes, rounding up (?)
*/
if (secretstore == NULL)
fatal("out of memory");
if (result != ISC_R_SUCCESS) {
goto failure;
}
if (result != ISC_R_SUCCESS) {
printf(";; Couldn't create key %s: %s\n",
}
if (secretstore != NULL)
}
static dig_searchlist_t *
make_searchlist_entry(char *domain) {
fatal("Memory allocation failure in %s:%d",
return (search);
}
/*
* Setup the system as a whole, reading key information and resolv.conf
* settings.
*/
void
setup_system(void) {
char *ptr;
char *input;
debug("setup_system()");
/* XXX Use lwres resolv.conf reader */
goto no_file;
if (get_servers &&
debug("got a nameserver line");
}
6) == 0) &&
(ndots == -1)) {
&ptr[6]);
debug("ndots is %d.",
ndots);
}
}
!= NULL) {
}
!= NULL) {
}
}
}
}
}
if (ndots == -1)
ndots = 1;
}
if (keyfile[0] != 0)
else if (keysecret[0] != 0)
}
static void
clear_searchlist(void) {
}
}
/*
* 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()");
/*
* Warning: This is not particularly good randomness. We'll
* just use random() now for getting id values, but doing so
* does NOT insure that id's cann't be guessed.
*/
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.
*/
}
/*
* Add EDNS0 option record to a message. Currently, the only supported
* option is UDP buffer size.
*/
static void
#ifdef DNS_OPT_NEWCODES_LIVE
#endif /* DNS_OPT_NEWCODES_LIVE */
)
{
#ifdef DNS_OPT_NEWCODES_LIVE
unsigned int i, optsize = 0;
#endif /* DNS_OPT_NEWCODES_LIVE */
debug("add_opt()");
if (dnssec)
#ifdef DNS_OPT_NEWCODES_LIVE
#endif /* DNS_OPT_NEWCODES_LIVE */
}
/*
* 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--;
}
}
/*
* 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_server_t *s;
dig_query_t *q;
void *ptr;
if (debugging) {
q = ISC_LIST_HEAD(lookup->q);
while (q != NULL) {
debug("query to %s still pending",
q->servname);
q = ISC_LIST_NEXT(q, link);
}
return (ISC_FALSE);
}
}
/*
* At this point, we know there are no queries on the lookup,
* so can make it go away also.
*/
debug("cleared");
while (s != NULL) {
debug("freeing server %p belonging to %p",
s, lookup);
ptr = s;
s = ISC_LIST_NEXT(s, link);
}
}
return (ISC_TRUE);
}
/*
* 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) {
} 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;
debug("followup_lookup()");
if (result != ISC_R_SUCCESS) {
if ((section == DNS_SECTION_ANSWER) &&
numLookups +=
return (numLookups);
}
for (;
result == ISC_R_SUCCESS;
{
{
continue;
result == ISC_R_SUCCESS;
{
char namestr[DNS_NAME_FORMATSIZE];
break;
sizeof(namestr));
/* Initialize lookup if we've not yet */
numLookups++;
if (!success) {
if (section == DNS_SECTION_ANSWER) {
} else {
}
}
}
}
}
numLookups +=
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);
/*
* Then we just did rootorg; there's nothing left.
*/
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));
}
/*
* 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.
*/
void
int len;
isc_buffer_t b;
if (lookup->new_search) {
debug("resetting lookup counter.");
lookup_counter = 0;
}
debug("cloning server list");
}
sizeof(lookup->onamespace));
/*
* 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.
*/
/* XXX New search here? */
}
/* 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)",
}
if (lookup->trace_root) {
} else {
isc_buffer_add(&b, len);
}
if (result != ISC_R_SUCCESS) {
fatal("'%s' is not in legal name syntax (%s)",
}
} else {
debug("using root origin");
if (!lookup->trace_root) {
isc_buffer_add(&b, len);
} else {
}
if (result != ISC_R_SUCCESS) {
fatal("'%s' is not a legal name "
}
}
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");
}
if (lookup->trace_root)
/*
* Force TCP mode if we're doing an xfr.
* XXX UDP ixfr's would be useful
*/
}
/* XXX add_soa */
/* XXX Insist this? */
debug("initializing keys");
}
fatal("memory allocation failure");
debug("starting to render the message");
#ifndef DNS_OPT_NEWCODES_LIVE
#else /* DNS_OPT_NEWCODES_LIVE */
#endif /* DNS_OPT_NEWCODES_LIVE */
#ifdef DNS_OPT_NEWCODES_LIVE
NULL);
MXNAME);
wirebuf);
}
}
optlist);
#else /* DNS_OPT_NEWCODES_LIVE */
#endif /* DNS_OPT_NEWCODES_LIVE */
}
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;
fatal("memory allocation failure");
}
/* XXX qrflag, print_query, etc... */
ISC_TRUE);
}
}
/*
* Event handler for send completion. Track send counter, and clear out
* the query if the send was canceled.
*/
static void
debug("send_done()");
sendcount--;
}
/*
* 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
}
isc_timer_detach(&l->timer);
NULL,
&l->interval,
l, &l->timer);
}
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 (specified_source &&
isc_sockaddr_pf(&bind_address))) {
printf(";; Skipping server %s, incompatible "
printf(";; No acceptable nameservers\n");
return;
}
return;
}
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_leafnode) {
debug("sending next, since searching");
}
}
/*
* 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;
debug("working on lookup %p, query %p",
/* XXX Check the sense of this, need assertion? */
sockcount++;
if (specified_source) {
} else {
}
link);
debug("recving with lookup=%p, query=%p, sock=%p",
query);
recvcount++;
}
link);
debug("sending a request");
sendcount++;
/*
* 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_leafnode) {
debug("sending next, since searching");
}
}
/*
* 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()");
query = l->current_query;
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);
cancel_lookup(l);
l->retries--;
requeue_lookup(l, ISC_TRUE);
}
} else {
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.
*/
debug("recving with lookup=%p, query=%p",
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 (include_question) {
link);
}
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
dig_lookup_t *l;
debug("connect_done()");
debug("in cancel handler");
sockcount--;
return;
}
char sockstr[ISC_SOCKADDR_FORMATSIZE];
debug("unsuccessful connection: %s",
sizeof(sockstr));
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;
}
}
/*
* 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
{
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");
continue;
}
/*
* 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 %d",
goto doexit;
goto next_rdata;
}
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 %d",
goto next_rdata;
}
if (query->second_rr_serial == 0) {
/*
* If the second RR was a non-SOA
* record, and we're getting any
* other SOA, then this is an
* AXFR, and we're done.
*/
debug("done, since axfr");
goto doexit;
}
/*
* 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);
}
/*
* 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;
dig_lookup_t *n, *l;
unsigned int local_timeout;
debug("recv_done()");
recvcount--;
isc_timer_touch(l->timer);
|| cancel_now) {
debug("no longer pending. Got %s",
return;
}
&msg);
debug("getting initial querysig");
l->sendmsg,
"dns_message_getquerytsig");
}
l->querysig);
if (l->msgcounter != 0)
l->msgcounter++;
}
debug("before parse starts");
if (l->besteffort)
else
if (result != ISC_R_SUCCESS &&
result != DNS_R_RECOVERABLE ) {
printf(";; Got bad packet: %s\n",
hex_dump(b);
cancel_lookup(l);
return;
}
if (result == DNS_R_RECOVERABLE)
printf(";; Warning: Message parser reports malformed "
"message packet.\n");
printf(";; Truncated, retrying in TCP mode.\n");
n = requeue_lookup(l, ISC_TRUE);
cancel_lookup(l);
return;
}
l->servfail_stops) {
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) ||
printf(";; Got SERVFAIL reply from %s, "
"trying next server\n",
return;
}
}
if (result != ISC_R_SUCCESS) {
printf(";; Couldn't verify signature: %s\n",
}
debug("freeing querysig buffer %p",
l->querysig);
isc_buffer_free(&l->querysig);
}
&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
*/
l->doing_xfr ) {
if (timeout == 0) {
if (l->tcp_mode)
else
} else {
else
}
debug("have local timeout of %d",
isc_interval_set(&l->interval,
local_timeout, 0);
NULL,
&l->interval,
}
}
if ((l->trace)||
(l->ns_search_only)) {
debug("in TRACE code");
ISC_TRUE);
query);
}
} else {
if (l->ns_search_only)
{
{
/*
* We didn't get an
* answer section,
* or else this is
* the first initial
* SOA query (in which
* case we will in fact
* get an answer
* section but it won't
* be the right one).
* In either case,
* our next query
* should be an NS.
*/
l->rdtype = dns_rdatatype_ns;
} else {
/*
* We got an answer
* section for our
* NS query! Yay!
* Now we shift gears,
* set the leafnode bit
* and look for SOAs
* in all the servers
* we got back in our
* answer section.
*/
l->rdtype = dns_rdatatype_soa;
DNS_SECTION_ANSWER) == 0)
{
}
}
}
if ((result != ISC_R_SUCCESS) ||
l->trace_root)
{
/*
* This is executed regardless
* of whether we're doing
* ns_search_only, but because
* of the way the logic works,
* it's mutually exclusive
* with the other call to
* followup_lookup above. This
* is a good thing because we
* want to call followup_lookup
* at most once per query.
*
* The idea here is that
* if we didn't get an answer
* section (or if it's the
* initial root query) then
* we want to take whatever is
* in the authority section and
* follow up with them.
*/
== 0)
{
}
}
}
ISC_TRUE);
query);
}
} else {
}
== ISC_R_SUCCESS) &&
(l->ns_search_only || l->ns_search_only_leafnode) &&
!l->trace_root ) {
}
if (l->pending)
debug("still pending.");
if (l->doing_xfr) {
isc_event_free (&event);
return;
}
if (! docancel)
if (docancel) {
cancel_lookup(l);
}
} else {
query);
}
cancel_lookup(l);
}
}
return;
}
/*
* In truth, we should never get into the CANCELED routine, since
* the cancel_lookup() routine clears the pending flag.
* XXX Is this true anymore, since the bulk changes?
*/
debug("in recv cancel handler");
return;
}
printf(";; communications error: %s\n",
sockcount--;
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.
*/
void
#ifdef USE_GETADDRINFO
int result;
#else
#endif
debug("get_address()");
/*
* Assume we have v4 if we don't have v6, since setup_libs
* fatal()'s out if we don't have either.
*/
else {
#ifdef USE_GETADDRINFO
if (!have_ipv6)
else if (!have_ipv4)
else
debug ("before getaddrinfo()");
if (result != 0) {
fatal("Couldn't find server '%s': %s",
}
#else
debug ("before gethostbyname()");
fatal("Couldn't find server '%s' (h_errno=%d)",
port);
#endif
}
}
/*
* 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) {
q = ISC_LIST_HEAD(current_lookup->q);
while (q != NULL) {
debug("cancelling query %p, belonging to %p",
q, current_lookup);
} else {
clear_query (q);
}
q = nq;
}
}
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) {
void *ptr;
dig_server_t *s;
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");
}
s = ISC_LIST_HEAD(server_list);
while (s != NULL) {
debug("freeing global server %p", s);
ptr = s;
s = ISC_LIST_NEXT(s, link);
}
debug("freeing commctx");
}
debug("freeing socketmgr");
}
debug("freeing timermgr");
}
}
if (is_dst_up) {
debug("destroy DST lib");
}
debug("detach from entropy");
}
if (memdebugging != 0)
}