dig.c revision 0c27b3fe77ac1d5094ba3521e8142d9e7973133f
/*
* Copyright (C) 2000-2016 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 */
#include <config.h>
#include <stdlib.h>
#include <time.h>
#include <ctype.h>
#include <isc/parseint.h>
#include <dns/fixedname.h>
#include <dns/masterdump.h>
#include <dns/rdataset.h>
#include <dns/rdatatype.h>
#include <dns/rdataclass.h>
#define ADD_STRING(b, s) { \
if (strlen(s) >= isc_buffer_availablelength(b)) \
return (ISC_R_NOSPACE); \
else \
isc_buffer_putstr(b, s); \
}
#define DIG_MAX_ADDRESSES 20
static char *argv0;
static int addresscount = 0;
static char domainopt[DNS_NAME_MAXTEXT];
static char hexcookie[81];
/*% rrcomments are neither explicitly enabled nor disabled by default */
static int rrcomments = 0;
/*% opcode text */
static const char * const opcodetext[] = {
"QUERY",
"IQUERY",
"STATUS",
"RESERVED3",
"NOTIFY",
"UPDATE",
"RESERVED6",
"RESERVED7",
"RESERVED8",
"RESERVED9",
"RESERVED10",
"RESERVED11",
"RESERVED12",
"RESERVED13",
"RESERVED14",
"RESERVED15"
};
static const char *
static char buf[64];
isc_buffer_t b;
buf[0] = '?';
return(buf);
}
return (buf + 1);
}
/*% print usage */
static void
"Usage: dig [@global-server] [domain] [q-type] [q-class] {q-opt}\n"
" {global-d-opt} host [@local-server] {local-d-opt}\n"
" [ host [@local-server] {local-d-opt} [...]]\n", fp);
}
ISC_PLATFORM_NORETURN_PRE static void
usage(void) ISC_PLATFORM_NORETURN_POST;
static void
usage(void) {
fputs("\nUse \"dig -h\" (or \"dig -h | more\") "
"for complete list of options\n", stderr);
exit(1);
}
/*% version */
static void
version(void) {
}
/*% help */
static void
help(void) {
"Where: domain is in the Domain Name System\n"
" q-class is one of (in,hs,ch,...) [default: in]\n"
" q-type is one of (a,any,mx,ns,soa,hinfo,axfr,txt,...) [default:a]\n"
" (Use ixfr=version for type ixfr)\n"
" q-opt is one of:\n"
" -4 (use IPv4 query transport only)\n"
" -6 (use IPv6 query transport only)\n"
" -c class (specify query class)\n"
" -f filename (batch mode)\n"
" -i (use IP6.INT for IPv6 reverse lookups)\n"
" -k keyfile (specify tsig key file)\n"
" -m (enable memory usage debugging)\n"
" -p port (specify port number)\n"
" -q name (specify query name)\n"
" -t type (specify query type)\n"
" -u (display times in usec instead of msec)\n"
" -x dot-notation (shortcut for reverse lookups)\n"
" -y [hmac:]name:key (specify named base64 tsig key)\n"
" d-opt is of the form +keyword[=value], where keyword is:\n"
" +[no]aaflag (Set AA flag in query (+[no]aaflag))\n"
" +[no]aaonly (Set AA flag in query (+[no]aaflag))\n"
" +[no]additional (Control display of additional section)\n"
" +[no]adflag (Set AD flag in query (default on))\n"
" +[no]all (Set or clear all display flags)\n"
" +[no]answer (Control display of answer section)\n"
" +[no]authority (Control display of authority section)\n"
" +[no]badcookie (Retry BADCOOKIE responses)\n"
" +[no]besteffort (Try to parse even illegal messages)\n"
" +bufsize=### (Set EDNS0 Max UDP packet size)\n"
" +[no]cdflag (Set checking disabled flag in query)\n"
" +[no]class (Control display of class in records)\n"
" +[no]cmd (Control display of command line)\n"
" +[no]comments (Control display of comment lines)\n"
" +[no]cookie (Add a COOKIE option to the request)\n"
" +[no]crypto (Control display of cryptographic "
"fields in records)\n"
" +[no]defname (Use search list (+[no]search))\n"
" +[no]dnssec (Request DNSSEC records)\n"
" +domain=### (Set default domainname)\n"
" +[no]dscp[=###] (Set the DSCP value to ### [0..63])\n"
" +[no]edns[=###] (Set EDNS version) [0]\n"
" +ednsflags=### (Set EDNS flag bits)\n"
" +[no]ednsnegotiation (Set EDNS version negotiation)\n"
" +ednsopt=###[:value] (Send specified EDNS option)\n"
" +noednsopt (Clear list of +ednsopt options)\n"
" +[no]expire (Request time to expire)\n"
" +[no]fail (Don't try next server on SERVFAIL)\n"
" +[no]header-only (Send query without a question section)\n"
" +[no]identify (ID responders in short answers)\n"
" +[no]ignore (Don't revert to TCP for TC responses.)\n"
" +[no]keepopen (Keep the TCP socket open between queries)\n"
" +[no]mapped (Allow mapped IPv4 over IPv6)\n"
" +[no]multiline (Print records in an expanded format)\n"
" +ndots=### (Set search NDOTS value)\n"
" +[no]nsid (Request Name Server ID)\n"
" +[no]nssearch (Search all authoritative nameservers)\n"
" +[no]onesoa (AXFR prints only one soa record)\n"
" +[no]opcode=### (Set the opcode of the request)\n"
" +[no]qr (Print question before sending)\n"
" +[no]question (Control display of question section)\n"
" +[no]rdflag (Recursive mode (+[no]recurse))\n"
" +[no]recurse (Recursive mode (+[no]rdflag))\n"
" +retry=### (Set number of UDP retries) [2]\n"
" +[no]rrcomments (Control display of per-record "
"comments)\n"
" +[no]search (Set whether to use searchlist)\n"
" +[no]short (Display nothing except short\n"
" form of answer)\n"
" +[no]showsearch (Search with intermediate results)\n"
#ifdef DIG_SIGCHASE
" +[no]sigchase (Chase DNSSEC signatures)\n"
#endif
" +[no]stats (Control display of statistics)\n"
" +subnet=addr (Set edns-client-subnet option)\n"
" +[no]tcp (TCP mode (+[no]vc))\n"
" +timeout=### (Set query timeout) [5]\n"
#if defined(DIG_SIGCHASE) && DIG_SIGCHASE_TD
" +[no]topdown (Do +sigchase in top-down mode)\n"
#endif
" +[no]trace (Trace delegation down from root [+dnssec])\n"
#ifdef DIG_SIGCHASE
" +trusted-key=#### (Trusted Key to use with +sigchase)\n"
#endif
" +tries=### (Set number of UDP attempts) [3]\n"
" +[no]ttlid (Control display of ttls in records)\n"
" +[no]ttlunits (Display TTLs in human-readable units)\n"
" +[no]unknownformat (Print RDATA in RFC 3597 \"unknown\" format)\n"
" +[no]vc (TCP mode (+[no]tcp))\n"
" +[no]zflag (Set Z flag in query)\n"
" global d-opts and servers (before host name) affect all queries.\n"
" local d-opts and servers (after host name) affect only that lookup.\n"
" -h (print help and exit)\n"
" -v (print version and exit)\n",
stdout);
}
/*%
* Callback from dighost.c to print the received message.
*/
void
char time_str[100];
char fromtext[ISC_SOCKADDR_FORMATSIZE];
if (use_usec)
else
"%a %b %d %H:%M:%S %Z %Y", &tmnow) > 0U)
printf(";; XFR size: %u records (messages %u, "
query->byte_count);
} else {
}
if (!validated)
puts(";; WARNING -- Some TSIG could not "
"be validated");
}
puts(";; WARNING -- TSIG key was not used.");
}
puts("");
if (use_usec)
"from %s(%s) in %ld us\n\n",
? query->byte_count
: (isc_uint64_t)bytes,
else
"from %s(%s) in %ld ms\n\n",
? query->byte_count
: (isc_uint64_t)bytes,
}
}
/*
* Callback from dighost.c to print that it is trying a server.
* Not used in dig.
* XXX print_trying
*/
void
}
/*%
* Internal print routine used to print short form replies.
*/
static isc_result_t
char store[sizeof("12345678901234567890")];
unsigned int styleflags = 0;
if (result != ISC_R_SUCCESS)
return (result);
}
/* Turn on rrcomments if explicitly enabled */
if (rrcomments > 0)
if (nocrypto)
if (result == ISC_R_NOSPACE)
return (result);
if (use_usec)
else
}
return (ISC_R_SUCCESS);
}
/*%
* short_form message print handler. Calls above say_message()
*/
static isc_result_t
{
if (result == ISC_R_NOMORE)
return (ISC_R_SUCCESS);
else if (result != ISC_R_SUCCESS)
return (result);
for (;;) {
while (loopresult == ISC_R_SUCCESS) {
buf);
if (result == ISC_R_NOSPACE)
return (result);
}
}
if (result == ISC_R_NOMORE)
break;
else if (result != ISC_R_SUCCESS)
return (result);
}
return (ISC_R_SUCCESS);
}
#ifdef DIG_SIGCHASE
{
unsigned int styleflags = 0;
return(ISC_FALSE);
if (ttlunits)
if (nottl)
if (noclass)
if (nocrypto)
/* Turn on rrcomments if explicitly enabled */
if (rrcomments > 0)
if (multiline) {
/* Turn on rrcomments if not explicitly disabled */
if (rrcomments >= 0)
}
24, 24, 24, 32, 80, 8,
splitwidth, mctx);
24, 24, 32, 40, 80, 8,
splitwidth, mctx);
else
24, 32, 40, 48, 80, 8,
splitwidth, mctx);
return(result);
}
#endif
/*
* Callback from dighost.c to print the reply from a server
*/
unsigned int styleflags = 0;
/* Turn on rrcomments if explicitly enabled */
if (rrcomments > 0)
if (ttlunits)
if (nottl)
if (noclass)
if (nocrypto)
if (multiline) {
/* Turn on rrcomments unless explicitly disabled */
if (rrcomments >= 0)
}
24, 24, 24, 32, 80, 8,
splitwidth, mctx);
24, 24, 32, 40, 80, 8,
splitwidth, mctx);
else
24, 32, 40, 48, 80, 8,
splitwidth, mctx);
if (!short_form)
}
flags = 0;
if (!headers) {
}
printf(";; Sending:\n");
else
printf(";; Got answer:\n");
if (headers) {
printf(";; ->>HEADER<<- opcode: %s, status: %s, "
"id: %u\n",
printf(";; flags:");
printf(" qr");
printf(" aa");
printf(" tc");
printf(" rd");
printf(" ra");
printf(" ad");
printf(" cd");
printf("; MBZ: 0x4");
printf("; QUERY: %u, ANSWER: %u, "
"AUTHORITY: %u, ADDITIONAL: %u\n",
printf(";; WARNING: recursion requested "
"but not available\n");
}
printf("\n;; WARNING: EDNS query returned status "
"%s - retry with '%s+noedns'\n",
printf(";; WARNING: Message has %u extra byte%s at "
}
if (result == ISC_R_NOSPACE) {
if (result == ISC_R_SUCCESS)
goto repopulate_buffer;
else
goto cleanup;
}
"dns_message_pseudosectiontotext");
}
if (!short_form) {
if (result == ISC_R_NOSPACE)
goto buftoosmall;
}
}
if (!short_form) {
if (result == ISC_R_NOSPACE)
goto buftoosmall;
} else {
if (result == ISC_R_NOSPACE)
goto buftoosmall;
}
}
if (!short_form) {
if (result == ISC_R_NOSPACE)
goto buftoosmall;
}
}
if (!short_form) {
if (result == ISC_R_NOSPACE)
goto buftoosmall;
/*
* Only print the signature on the first record.
*/
if (headers) {
msg,
if (result == ISC_R_NOSPACE)
goto buftoosmall;
"dns_message_pseudosectiontotext");
msg,
if (result == ISC_R_NOSPACE)
goto buftoosmall;
"dns_message_pseudosectiontotext");
}
}
}
printf("\n");
(char *)isc_buffer_base(buf));
return (result);
}
/*%
* print the greeting message when the program first starts up.
*/
static void
int i;
int remaining;
if (printcmd) {
i = 1;
while (i < argc) {
}
if (first && addresscount != 0) {
"; (%d server%s found)\n",
}
if (first) {
";; global options:%s%s\n",
}
}
}
/*%
* We're not using isc_commandline_parse() here since the command line
* syntax of dig is quite a bit different from that which can be described
* by that routine.
* XXX doc options
*/
static void
{
char option_store[256];
size_t n;
ptr = option_store;
return;
}
cmd += 2;
}
#define FULLCHECK(A) \
do { \
goto invalid_option; \
} while (0)
#define FULLCHECK2(A, B) \
do { \
goto invalid_option; \
} while (0)
switch (cmd[0]) {
case 'a':
switch (cmd[1]) {
case 'a': /* aaonly / aaflag */
break;
case 'd':
switch (cmd[2]) {
case 'd': /* additional */
FULLCHECK("additional");
break;
case 'f': /* adflag */
case '\0': /* +ad is a synonym for +adflag */
FULLCHECK("adflag");
break;
default:
goto invalid_option;
}
break;
case 'l': /* all */
FULLCHECK("all");
break;
case 'n': /* answer */
FULLCHECK("answer");
break;
case 'u': /* authority */
FULLCHECK("authority");
break;
default:
goto invalid_option;
}
break;
case 'b':
switch (cmd[1]) {
case 'a':/* badcookie */
FULLCHECK("badcookie");
break;
case 'e':/* besteffort */
FULLCHECK("besteffort");
break;
case 'u':/* bufsize */
FULLCHECK("bufsize");
goto need_value;
if (!state)
goto invalid_option;
"buffer size");
if (result != ISC_R_SUCCESS)
fatal("Couldn't parse buffer size");
break;
default:
goto invalid_option;
}
break;
case 'c':
switch (cmd[1]) {
case 'd':/* cdflag */
switch (cmd[2]) {
case 'f': /* cdflag */
case '\0': /* +cd is a synonym for +cdflag */
FULLCHECK("cdflag");
break;
default:
goto invalid_option;
}
break;
case 'l': /* class */
/* keep +cl for backwards compatibility */
break;
case 'm': /* cmd */
FULLCHECK("cmd");
break;
case 'o': /* comments */
switch (cmd[2]) {
case 'm':
FULLCHECK("comments");
if (lookup == default_lookup)
break;
case 'o': /* cookie */
FULLCHECK("cookie");
sizeof(hexcookie));
if (n >= sizeof(hexcookie))
fatal("COOKIE data too large");
} else
break;
default:
goto invalid_option;
}
break;
case 'r':
FULLCHECK("crypto");
break;
default:
goto invalid_option;
}
break;
case 'd':
switch (cmd[1]) {
case 'e': /* defname */
FULLCHECK("defname");
}
break;
case 'n': /* dnssec */
FULLCHECK("dnssec");
break;
case 'o': /* domain */
FULLCHECK("domain");
goto need_value;
if (!state)
goto invalid_option;
break;
case 's': /* dscp */
FULLCHECK("dscp");
if (!state) {
break;
}
goto need_value;
if (result != ISC_R_SUCCESS)
fatal("Couldn't parse DSCP value");
break;
default:
goto invalid_option;
}
break;
case 'e':
switch (cmd[1]) {
case 'd':
switch(cmd[2]) {
case 'n':
switch (cmd[3]) {
case 's':
switch (cmd[4]) {
case 0:
FULLCHECK("edns");
if (!state) {
break;
}
break;
}
255,
"edns");
if (result != ISC_R_SUCCESS)
fatal("Couldn't parse "
"edns");
break;
case 'f':
FULLCHECK("ednsflags");
if (!state) {
break;
}
break;
}
0xffff,
"ednsflags");
if (result != ISC_R_SUCCESS)
fatal("Couldn't parse "
"ednsflags");
break;
case 'n':
FULLCHECK("ednsnegotiation");
break;
case 'o':
FULLCHECK("ednsopt");
if (!state) {
lookup->ednsoptscnt = 0;
break;
}
fatal("ednsopt no "
"code point "
"specified");
break;
default:
goto invalid_option;
}
break;
default:
goto invalid_option;
}
break;
default:
goto invalid_option;
}
break;
case 'x':
FULLCHECK("expire");
break;
default:
goto invalid_option;
}
break;
case 'f': /* fail */
FULLCHECK("fail");
break;
case 'h':
FULLCHECK("header-only");
break;
case 'i':
switch (cmd[1]) {
case 'd': /* identify */
FULLCHECK("identify");
break;
case 'g': /* ignore */
default: /*
* Inherits default for compatibility (+[no]i*).
*/
FULLCHECK("ignore");
}
break;
case 'k':
FULLCHECK("keepopen");
break;
case 'm': /* multiline */
switch (cmd[1]) {
case 'a':
FULLCHECK("mapped");
break;
case 'u':
FULLCHECK("multiline");
break;
default:
goto invalid_option;
}
break;
case 'n':
switch (cmd[1]) {
case 'd': /* ndots */
FULLCHECK("ndots");
goto need_value;
if (!state)
goto invalid_option;
if (result != ISC_R_SUCCESS)
fatal("Couldn't parse ndots");
break;
case 's':
switch (cmd[2]) {
case 'i': /* nsid */
FULLCHECK("nsid");
break;
case 's': /* nssearch */
FULLCHECK("nssearch");
if (state) {
rrcomments = 0;
}
break;
default:
goto invalid_option;
}
break;
default:
goto invalid_option;
}
break;
case 'o':
switch (cmd[1]) {
case 'n':
FULLCHECK("onesoa");
break;
case 'p':
FULLCHECK("opcode");
if (!state) {
break;
}
goto need_value;
for (num = 0;
num++) {
break;
}
if (num < 16) {
break;
}
if (result != ISC_R_SUCCESS)
fatal("Couldn't parse opcode");
break;
default:
goto invalid_option;
}
break;
case 'q':
switch (cmd[1]) {
case 'r': /* qr */
FULLCHECK("qr");
break;
case 'u': /* question */
FULLCHECK("question");
if (lookup == default_lookup)
break;
default:
goto invalid_option;
}
break;
case 'r':
switch (cmd[1]) {
case 'd': /* rdflag */
FULLCHECK("rdflag");
break;
case 'e':
switch (cmd[2]) {
case 'c': /* recurse */
FULLCHECK("recurse");
break;
case 't': /* retry / retries */
goto need_value;
if (!state)
goto invalid_option;
if (result != ISC_R_SUCCESS)
fatal("Couldn't parse retries");
break;
default:
goto invalid_option;
}
break;
case 'r': /* rrcomments */
FULLCHECK("rrcomments");
break;
default:
goto invalid_option;
}
break;
case 's':
switch (cmd[1]) {
case 'e': /* search */
FULLCHECK("search");
}
break;
case 'h':
goto invalid_option;
switch (cmd[3]) {
case 'r': /* short */
FULLCHECK("short");
short_form = state;
if (state) {
rrcomments = -1;
}
break;
case 'w': /* showsearch */
FULLCHECK("showsearch");
showsearch = state;
}
break;
default:
goto invalid_option;
}
break;
#ifdef DIG_SIGCHASE
case 'i': /* sigchase */
FULLCHECK("sigchase");
break;
#endif
case 'p': /* split */
FULLCHECK("split");
goto invalid_option;
if (!state) {
splitwidth = 0;
break;
break;
1023, "split");
if (splitwidth % 4 != 0) {
"a multiple of 4; adjusting "
"to %d\n", splitwidth);
}
/*
* There is an adjustment done in the
* totext_<rrtype>() functions which causes
* splitwidth to shrink. This is okay when we're
* using the default width but incorrect in this
* case, so we correct for it
*/
if (splitwidth)
splitwidth += 3;
if (result != ISC_R_SUCCESS)
fatal("Couldn't parse split");
break;
case 't': /* stats */
FULLCHECK("stats");
break;
case 'u': /* subnet */
FULLCHECK("subnet");
goto need_value;
if (!state) {
}
break;
}
if (result != ISC_R_SUCCESS)
fatal("Couldn't parse client");
break;
default:
goto invalid_option;
}
break;
case 't':
switch (cmd[1]) {
case 'c': /* tcp */
FULLCHECK("tcp");
if (!is_batchfile) {
}
break;
case 'i': /* timeout */
FULLCHECK("timeout");
goto need_value;
if (!state)
goto invalid_option;
"timeout");
if (result != ISC_R_SUCCESS)
fatal("Couldn't parse timeout");
if (timeout == 0)
timeout = 1;
break;
#if DIG_SIGCHASE_TD
case 'o': /* topdown */
FULLCHECK("topdown");
break;
#endif
case 'r':
switch (cmd[2]) {
case 'a': /* trace */
FULLCHECK("trace");
if (state) {
rrcomments = 0;
}
break;
case 'i': /* tries */
FULLCHECK("tries");
goto need_value;
if (!state)
goto invalid_option;
MAXTRIES, "tries");
if (result != ISC_R_SUCCESS)
fatal("Couldn't parse tries");
break;
#ifdef DIG_SIGCHASE
case 'u': /* trusted-key */
FULLCHECK("trusted-key");
goto need_value;
if (!state)
goto invalid_option;
sizeof(trustedkey));
if (n >= sizeof(trustedkey))
fatal("trusted key too large");
break;
#endif
default:
goto invalid_option;
}
break;
case 't':
switch (cmd[2]) {
case 'l':
switch (cmd[3]) {
case 0:
case 'i': /* ttlid */
break;
case 'u': /* ttlunits */
FULLCHECK("ttlunits");
break;
default:
goto invalid_option;
}
break;
default:
goto invalid_option;
}
break;
default:
goto invalid_option;
}
break;
case 'u':
FULLCHECK("unknownformat");
break;
case 'v':
FULLCHECK("vc");
if (!is_batchfile) {
}
break;
case 'z': /* zflag */
FULLCHECK("zflag");
break;
default:
option);
usage();
}
return;
}
/*%
* #ISC_TRUE returned if value was used
*/
static const char *single_dash_opts = "46dhimnuv";
static const char *dash_opts = "46bcdfhikmnptvyx";
static isc_boolean_t
{
/*
* Since the -[46dhimnuv] options do not take an argument,
* if they appear as the first character(s) of a q-opt.
*/
switch (opt) {
case '4':
if (have_ipv4) {
} else {
fatal("can't find IPv4 networking");
/* NOTREACHED */
return (ISC_FALSE);
}
break;
case '6':
if (have_ipv6) {
} else {
fatal("can't find IPv6 networking");
/* NOTREACHED */
return (ISC_FALSE);
}
break;
case 'd':
FULLCHECK("debug");
return (ISC_FALSE);
} else
break;
case 'h':
help();
exit(0);
break;
case 'i':
break;
case 'm': /* memdebug */
/* memdebug is handled in preparse_args() */
break;
case 'n':
/* deprecated */
break;
case 'u':
break;
case 'v':
version();
exit(0);
break;
}
else
return (ISC_FALSE);
}
} else {
}
goto invalid_option;
switch (opt) {
case 'b':
"port number");
if (result != ISC_R_SUCCESS)
fatal("Couldn't parse port number");
*hash = '\0';
} else
srcport = 0;
} else {
*hash = '#';
}
*hash = '#';
return (value_from_next);
case 'c':
if ((*lookup)->rdclassset) {
}
(isc_textregion_t *)&tr);
if (result == ISC_R_SUCCESS) {
} else
"invalid class %s\n",
value);
return (value_from_next);
case 'f':
return (value_from_next);
case 'k':
return (value_from_next);
case 'p':
if (result != ISC_R_SUCCESS)
fatal("Couldn't parse port number");
return (value_from_next);
case 'q':
if (!config_only) {
if (*need_clone)
ISC_TRUE);
*need_clone = ISC_TRUE;
(*lookup)->ns_search_only);
if (*firstarg) {
}
}
return (value_from_next);
case 't':
} else {
(isc_textregion_t *)&tr);
if (result == ISC_R_SUCCESS &&
rdtype == dns_rdatatype_ixfr) {
}
}
if (result == ISC_R_SUCCESS) {
"extra type option\n");
}
if (rdtype == dns_rdatatype_ixfr) {
MAXSERIAL, "serial number");
if (result != ISC_R_SUCCESS)
fatal("Couldn't parse serial number");
if (!(*lookup)->tcp_mode_set)
} else {
if (!config_only)
if (rdtype == dns_rdatatype_axfr) {
}
}
} else
"invalid type %s\n",
value);
return (value_from_next);
case 'y':
usage();
}
usage();
} else {
digestbits = 0;
}
return (value_from_next);
case 'x':
if (*need_clone)
*need_clone = ISC_TRUE;
(*lookup)->ns_search_only);
if (!(*lookup)->rdclassset)
if (*firstarg) {
}
} else {
exit(1);
}
return (value_from_next);
default:
usage();
}
/* NOTREACHED */
return (ISC_FALSE);
}
/*%
* Because we may be trying to do memory allocation recording, we're going
* to need to parse the arguments for the -m *before* we start the main
* argument parsing routine.
*
* I'd prefer not to have to do this, but I am not quite sure how else to
* fix the problem. Argument parsing in dig involves memory allocation
* by its nature, so it can't be done in the main argument parser.
*/
static void
int rc;
char **rv;
char *option;
if (rv[0][0] != '-')
continue;
switch (option[0]) {
case 'm':
break;
case '4':
if (ipv6only)
fatal("only one of -4 and -6 allowed");
break;
case '6':
if (ipv4only)
fatal("only one of -4 and -6 allowed");
break;
}
}
}
}
static void
{
int bargc;
char *bargv[64];
int rc;
char **rv;
#ifndef NOPOSIX
char *homedir;
char rcfile[256];
#endif
char *input;
int i;
/*
* The semantics for parsing the args is a bit complex; if
* we don't have a host yet, make the arg apply globally,
* otherwise make it apply to the latest host. This is
* a bit different than the previous versions, but should
* form a consistent user interface.
*
* First, create a "default lookup" which won't actually be used
* anywhere, except for cloning into new lookups
*/
debug("parse_args()");
if (!is_batchfile) {
debug("making new lookup");
default_lookup->edns = 0;
#ifndef NOPOSIX
/*
* Treat ${HOME}/.digrc as a special batchfile
*/
unsigned int n;
homedir);
if (n < sizeof(rcfile))
}
batchfp) != 0) {
bargc = 1;
(bargc < 62)) {
bargc++;
}
for(i = 0; i < bargc; i++)
debug(".digrc argv %d: %s",
i, bargv[i]);
(char **)bargv);
}
}
#endif
}
if (is_batchfile && !config_only) {
/* Processing '-f batchfile'. */
} else
break;
if (rv[0][0] == '@') {
if (is_batchfile && !config_only) {
&result);
if (addresscount == 0) {
"for '%s': %s: skipping "
return;
}
} else {
NULL);
if (addresscount == 0)
fatal("no valid addresses for '%s'\n",
&rv[0][1]);
}
} else if (rv[0][0] == '+') {
lookup);
} else if (rv[0][0] == '-') {
if (rc <= 1) {
rc--;
rv++;
}
} else {
rc--;
rv++;
}
}
} else {
/*
* Anything which isn't an option
*/
if (open_type_class) {
} else {
(isc_textregion_t *)&tr);
if (result == ISC_R_SUCCESS &&
rdtype == dns_rdatatype_ixfr) {
"ixfr requires a "
"serial number\n");
continue;
}
}
if (result == ISC_R_SUCCESS) {
"extra type option\n");
}
if (rdtype == dns_rdatatype_ixfr) {
&rv[0][5],
"serial number");
if (result != ISC_R_SUCCESS)
fatal("Couldn't parse "
"serial number");
if (!lookup->tcp_mode_set)
} else {
if (rdtype ==
}
}
continue;
}
(isc_textregion_t *)&tr);
if (result == ISC_R_SUCCESS) {
if (lookup->rdclassset) {
"extra class option\n");
}
continue;
}
}
if (!config_only) {
if (need_clone)
ISC_TRUE);
if (firstarg) {
}
}
/* XXX Error message */
}
}
/*
* If we have a batchfile, seed the lookup list with the
* first entry, then trust the callback in dighost_shutdown
* to get the rest
*/
else
if (exitcode < 8)
exitcode = 8;
fatal("couldn't open specified batch file");
}
/* XXX Remove code dup from shutdown code */
bargc = 1;
goto next_line;
bargc++;
}
for(i = 0; i < bargc; i++)
return;
}
return;
}
/*
* If no lookup specified, search for root
*/
if (need_clone)
if (firstarg) {
}
}
if (!need_clone)
}
/*
* Callback from dighost.c to allow program-specific shutdown code.
* Here, we're possibly reading from a batch file, then shutting down
* for real if there's nothing in the batch file to read.
*/
void
dighost_shutdown(void) {
int bargc;
char *bargv[16];
char *input;
int i;
return;
}
return;
}
bargc = 1;
bargc++;
}
for(i = 0; i < bargc; i++)
start_lookup();
} else {
return;
}
}
/*% Main processing routine for dig */
int
debug("main()");
result = isc_app_start();
setup_libs();
if (keyfile[0] != 0)
else if (keysecret[0] != 0)
if (domainopt[0] != '\0') {
}
isc_app_run();
}
#ifdef DIG_SIGCHASE
#endif
cancel_all();
destroy_libs();
return (exitcode);
}