xref: /openbsd-src/usr.bin/dig/host.c (revision e9ec17621338d550f8b21353be6a0060c10cd5bd)
15185a700Sflorian /*
25185a700Sflorian  * Copyright (C) Internet Systems Consortium, Inc. ("ISC")
35185a700Sflorian  *
45185a700Sflorian  * Permission to use, copy, modify, and/or distribute this software for any
55185a700Sflorian  * purpose with or without fee is hereby granted, provided that the above
65185a700Sflorian  * copyright notice and this permission notice appear in all copies.
75185a700Sflorian  *
85185a700Sflorian  * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
95185a700Sflorian  * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
105185a700Sflorian  * AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
115185a700Sflorian  * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
125185a700Sflorian  * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
135185a700Sflorian  * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
145185a700Sflorian  * PERFORMANCE OF THIS SOFTWARE.
155185a700Sflorian  */
165185a700Sflorian 
175185a700Sflorian /*! \file */
18*e9ec1762Sflorian #include <sys/types.h>
195185a700Sflorian 
205185a700Sflorian #include <err.h>
215185a700Sflorian #include <limits.h>
225185a700Sflorian #include <locale.h>
235185a700Sflorian #include <stdlib.h>
245185a700Sflorian #include <string.h>
255185a700Sflorian #include <unistd.h>
264465bcfbSjsg #include <time.h>
274465bcfbSjsg #include <stdint.h>
285185a700Sflorian 
295185a700Sflorian #include <isc/app.h>
305185a700Sflorian #include <isc/util.h>
315185a700Sflorian 
325185a700Sflorian #include <dns/fixedname.h>
335185a700Sflorian #include <dns/message.h>
345185a700Sflorian #include <dns/name.h>
355185a700Sflorian #include <dns/rdata.h>
365185a700Sflorian #include <dns/rdataclass.h>
375185a700Sflorian #include <dns/rdataset.h>
385185a700Sflorian #include <dns/rdatatype.h>
395185a700Sflorian 
405185a700Sflorian #include "dig.h"
415185a700Sflorian 
421fb015a8Sflorian static int short_form = 1, listed_server = 0;
431fb015a8Sflorian static int default_lookups = 1;
445185a700Sflorian static int seen_error = -1;
451fb015a8Sflorian static int list_addresses = 1;
465185a700Sflorian static dns_rdatatype_t list_type = dns_rdatatype_a;
471fb015a8Sflorian static int printed_server = 0;
481fb015a8Sflorian static int ipv4only = 0, ipv6only = 0;
495185a700Sflorian 
505185a700Sflorian static const char *opcodetext[] = {
515185a700Sflorian 	"QUERY",
525185a700Sflorian 	"IQUERY",
535185a700Sflorian 	"STATUS",
545185a700Sflorian 	"RESERVED3",
555185a700Sflorian 	"NOTIFY",
565185a700Sflorian 	"UPDATE",
575185a700Sflorian 	"RESERVED6",
585185a700Sflorian 	"RESERVED7",
595185a700Sflorian 	"RESERVED8",
605185a700Sflorian 	"RESERVED9",
615185a700Sflorian 	"RESERVED10",
625185a700Sflorian 	"RESERVED11",
635185a700Sflorian 	"RESERVED12",
645185a700Sflorian 	"RESERVED13",
655185a700Sflorian 	"RESERVED14",
665185a700Sflorian 	"RESERVED15"
675185a700Sflorian };
685185a700Sflorian 
695185a700Sflorian static const char *rcodetext[] = {
705185a700Sflorian 	"NOERROR",
715185a700Sflorian 	"FORMERR",
725185a700Sflorian 	"SERVFAIL",
735185a700Sflorian 	"NXDOMAIN",
745185a700Sflorian 	"NOTIMP",
755185a700Sflorian 	"REFUSED",
765185a700Sflorian 	"YXDOMAIN",
775185a700Sflorian 	"YXRRSET",
785185a700Sflorian 	"NXRRSET",
795185a700Sflorian 	"NOTAUTH",
805185a700Sflorian 	"NOTZONE",
815185a700Sflorian 	"RESERVED11",
825185a700Sflorian 	"RESERVED12",
835185a700Sflorian 	"RESERVED13",
845185a700Sflorian 	"RESERVED14",
855185a700Sflorian 	"RESERVED15",
865185a700Sflorian 	"BADVERS"
875185a700Sflorian };
885185a700Sflorian 
895185a700Sflorian struct rtype {
905185a700Sflorian 	unsigned int type;
915185a700Sflorian 	const char *text;
925185a700Sflorian };
935185a700Sflorian 
945185a700Sflorian static struct rtype rtypes[] = {
955185a700Sflorian 	{ 1, 	"has address" },
965185a700Sflorian 	{ 2, 	"name server" },
975185a700Sflorian 	{ 5, 	"is an alias for" },
985185a700Sflorian 	{ 11,	"has well known services" },
995185a700Sflorian 	{ 12,	"domain name pointer" },
1005185a700Sflorian 	{ 13,	"host information" },
1015185a700Sflorian 	{ 15,	"mail is handled by" },
1025185a700Sflorian 	{ 16,	"descriptive text" },
1035185a700Sflorian 	{ 19,	"x25 address" },
1045185a700Sflorian 	{ 20,	"ISDN address" },
1055185a700Sflorian 	{ 24,	"has signature" },
1065185a700Sflorian 	{ 25,	"has key" },
1075185a700Sflorian 	{ 28,	"has IPv6 address" },
1085185a700Sflorian 	{ 29,	"location" },
1095185a700Sflorian 	{ 0, NULL }
1105185a700Sflorian };
1115185a700Sflorian 
1125185a700Sflorian static char *
rcode_totext(dns_rcode_t rcode)1135185a700Sflorian rcode_totext(dns_rcode_t rcode)
1145185a700Sflorian {
1155185a700Sflorian 	static char buf[sizeof("?65535")];
1165185a700Sflorian 	union {
1175185a700Sflorian 		const char *consttext;
1185185a700Sflorian 		char *deconsttext;
1195185a700Sflorian 	} totext;
1205185a700Sflorian 
1215185a700Sflorian 	if (rcode >= (sizeof(rcodetext)/sizeof(rcodetext[0]))) {
1225185a700Sflorian 		snprintf(buf, sizeof(buf), "?%u", rcode);
1235185a700Sflorian 		totext.deconsttext = buf;
1245185a700Sflorian 	} else
1255185a700Sflorian 		totext.consttext = rcodetext[rcode];
1265185a700Sflorian 	return totext.deconsttext;
1275185a700Sflorian }
1285185a700Sflorian 
1295185a700Sflorian static __dead void
1305185a700Sflorian show_usage(void);
1315185a700Sflorian 
1325185a700Sflorian static void
show_usage(void)1335185a700Sflorian show_usage(void) {
1345185a700Sflorian 	fputs(
1355185a700Sflorian "usage: host [-46aCdilrsTVvw] [-c class] [-m flag] [-N ndots] [-R number]\n"
1365185a700Sflorian "            [-t type] [-W wait] name [server]\n", stderr);
1375185a700Sflorian 	exit(1);
1385185a700Sflorian }
1395185a700Sflorian 
1405185a700Sflorian static void
host_shutdown(void)1415185a700Sflorian host_shutdown(void) {
1425185a700Sflorian 	(void) isc_app_shutdown();
1435185a700Sflorian }
1445185a700Sflorian 
1455185a700Sflorian static void
received(unsigned int bytes,struct sockaddr_storage * from,dig_query_t * query)146b1a294b5Sflorian received(unsigned int bytes, struct sockaddr_storage *from, dig_query_t *query) {
1477238a213Sflorian 	struct timespec now;
1485185a700Sflorian 
1495185a700Sflorian 	if (!short_form) {
1505185a700Sflorian 		char fromtext[ISC_SOCKADDR_FORMATSIZE];
1515185a700Sflorian 		isc_sockaddr_format(from, fromtext, sizeof(fromtext));
152b53d8310Sflorian 		clock_gettime(CLOCK_MONOTONIC, &now);
153427f8978Sflorian 		printf("Received %u bytes from %s in %lld ms\n",
154427f8978Sflorian 		    bytes, fromtext, uelapsed(&now, &query->time_sent)/1000);
1555185a700Sflorian 	}
1565185a700Sflorian }
1575185a700Sflorian 
1585185a700Sflorian static void
trying(char * frm,dig_lookup_t * lookup)1595185a700Sflorian trying(char *frm, dig_lookup_t *lookup) {
1605185a700Sflorian 	UNUSED(lookup);
1615185a700Sflorian 
1625185a700Sflorian 	if (!short_form)
1635185a700Sflorian 		printf("Trying \"%s\"\n", frm);
1645185a700Sflorian }
1655185a700Sflorian 
1665185a700Sflorian static void
say_message(dns_name_t * name,const char * msg,dns_rdata_t * rdata,dig_query_t * query)1675185a700Sflorian say_message(dns_name_t *name, const char *msg, dns_rdata_t *rdata,
1685185a700Sflorian 	    dig_query_t *query)
1695185a700Sflorian {
1705185a700Sflorian 	isc_buffer_t *b = NULL;
1715185a700Sflorian 	char namestr[DNS_NAME_FORMATSIZE];
1725185a700Sflorian 	isc_region_t r;
1735185a700Sflorian 	isc_result_t result;
1745185a700Sflorian 	unsigned int bufsize = BUFSIZ;
1755185a700Sflorian 
1765185a700Sflorian 	dns_name_format(name, namestr, sizeof(namestr));
1775185a700Sflorian  retry:
1785185a700Sflorian 	result = isc_buffer_allocate(&b, bufsize);
1795185a700Sflorian 	check_result(result, "isc_buffer_allocate");
1805185a700Sflorian 	result = dns_rdata_totext(rdata, NULL, b);
1815185a700Sflorian 	if (result == ISC_R_NOSPACE) {
1825185a700Sflorian 		isc_buffer_free(&b);
1835185a700Sflorian 		bufsize *= 2;
1845185a700Sflorian 		goto retry;
1855185a700Sflorian 	}
1865185a700Sflorian 	check_result(result, "dns_rdata_totext");
1875185a700Sflorian 	isc_buffer_usedregion(b, &r);
1885185a700Sflorian 	if (query->lookup->identify_previous_line) {
1895185a700Sflorian 		printf("Nameserver %s:\n\t",
1905185a700Sflorian 			query->servname);
1915185a700Sflorian 	}
1925185a700Sflorian 	printf("%s %s %.*s", namestr,
1935185a700Sflorian 	       msg, (int)r.length, (char *)r.base);
1945185a700Sflorian 	if (query->lookup->identify) {
1955185a700Sflorian 		printf(" on server %s", query->servname);
1965185a700Sflorian 	}
1975185a700Sflorian 	printf("\n");
1985185a700Sflorian 	isc_buffer_free(&b);
1995185a700Sflorian }
2005185a700Sflorian static isc_result_t
printsection(dns_message_t * msg,dns_section_t sectionid,const char * section_name,int headers,dig_query_t * query)2015185a700Sflorian printsection(dns_message_t *msg, dns_section_t sectionid,
2021fb015a8Sflorian 	     const char *section_name, int headers,
2035185a700Sflorian 	     dig_query_t *query)
2045185a700Sflorian {
2055185a700Sflorian 	dns_name_t *name, *print_name;
2065185a700Sflorian 	dns_rdataset_t *rdataset;
2075185a700Sflorian 	dns_rdata_t rdata = DNS_RDATA_INIT;
2085185a700Sflorian 	isc_buffer_t target;
2095185a700Sflorian 	isc_result_t result, loopresult;
2105185a700Sflorian 	isc_region_t r;
2115185a700Sflorian 	dns_name_t empty_name;
2125185a700Sflorian 	char tbuf[4096];
2131fb015a8Sflorian 	int first;
2141fb015a8Sflorian 	int no_rdata;
2155185a700Sflorian 
2165185a700Sflorian 	if (sectionid == DNS_SECTION_QUESTION)
2171fb015a8Sflorian 		no_rdata = 1;
2185185a700Sflorian 	else
2191fb015a8Sflorian 		no_rdata = 0;
2205185a700Sflorian 
2215185a700Sflorian 	if (headers)
2225185a700Sflorian 		printf(";; %s SECTION:\n", section_name);
2235185a700Sflorian 
2245185a700Sflorian 	dns_name_init(&empty_name, NULL);
2255185a700Sflorian 
2265185a700Sflorian 	result = dns_message_firstname(msg, sectionid);
2275185a700Sflorian 	if (result == ISC_R_NOMORE)
2285185a700Sflorian 		return (ISC_R_SUCCESS);
2295185a700Sflorian 	else if (result != ISC_R_SUCCESS)
2305185a700Sflorian 		return (result);
2315185a700Sflorian 
2325185a700Sflorian 	for (;;) {
2335185a700Sflorian 		name = NULL;
2345185a700Sflorian 		dns_message_currentname(msg, sectionid, &name);
2355185a700Sflorian 
2365185a700Sflorian 		isc_buffer_init(&target, tbuf, sizeof(tbuf));
2371fb015a8Sflorian 		first = 1;
2385185a700Sflorian 		print_name = name;
2395185a700Sflorian 
2405185a700Sflorian 		for (rdataset = ISC_LIST_HEAD(name->list);
2415185a700Sflorian 		     rdataset != NULL;
2425185a700Sflorian 		     rdataset = ISC_LIST_NEXT(rdataset, link)) {
2435185a700Sflorian 			if (query->lookup->rdtype == dns_rdatatype_axfr &&
2445185a700Sflorian 			    !((!list_addresses &&
2455185a700Sflorian 			       (list_type == dns_rdatatype_any ||
2465185a700Sflorian 				rdataset->type == list_type)) ||
2475185a700Sflorian 			      (list_addresses &&
2485185a700Sflorian 			       (rdataset->type == dns_rdatatype_a ||
2495185a700Sflorian 				rdataset->type == dns_rdatatype_aaaa ||
2505185a700Sflorian 				rdataset->type == dns_rdatatype_ns ||
2515185a700Sflorian 				rdataset->type == dns_rdatatype_ptr))))
2525185a700Sflorian 				continue;
2535185a700Sflorian 			if (!short_form) {
2545185a700Sflorian 				result = dns_rdataset_totext(rdataset,
2555185a700Sflorian 							     print_name,
2561fb015a8Sflorian 							     0,
2575185a700Sflorian 							     no_rdata,
2585185a700Sflorian 							     &target);
2595185a700Sflorian 				if (result != ISC_R_SUCCESS)
2605185a700Sflorian 					return (result);
2615185a700Sflorian 				UNUSED(first); /* Shut up compiler. */
2625185a700Sflorian 			} else {
2635185a700Sflorian 				loopresult = dns_rdataset_first(rdataset);
2645185a700Sflorian 				while (loopresult == ISC_R_SUCCESS) {
2655185a700Sflorian 					struct rtype *t;
2665185a700Sflorian 					const char *rtt;
2675185a700Sflorian 					char typebuf[DNS_RDATATYPE_FORMATSIZE];
2685185a700Sflorian 					char typebuf2[DNS_RDATATYPE_FORMATSIZE
2695185a700Sflorian 						     + 20];
2705185a700Sflorian 					dns_rdataset_current(rdataset, &rdata);
2715185a700Sflorian 
2725185a700Sflorian 					for (t = rtypes; t->text != NULL; t++) {
2735185a700Sflorian 						if (t->type == rdata.type) {
2745185a700Sflorian 							rtt = t->text;
2755185a700Sflorian 							goto found;
2765185a700Sflorian 						}
2775185a700Sflorian 					}
2785185a700Sflorian 
2795185a700Sflorian 					dns_rdatatype_format(rdata.type,
2805185a700Sflorian 							     typebuf,
2815185a700Sflorian 							     sizeof(typebuf));
2825185a700Sflorian 					snprintf(typebuf2, sizeof(typebuf2),
2835185a700Sflorian 						 "has %s record", typebuf);
2845185a700Sflorian 					rtt = typebuf2;
2855185a700Sflorian 				found:
2865185a700Sflorian 					say_message(print_name, rtt,
2875185a700Sflorian 						    &rdata, query);
2885185a700Sflorian 					dns_rdata_reset(&rdata);
2895185a700Sflorian 					loopresult =
2905185a700Sflorian 						dns_rdataset_next(rdataset);
2915185a700Sflorian 				}
2925185a700Sflorian 			}
2935185a700Sflorian 		}
2945185a700Sflorian 		if (!short_form) {
2955185a700Sflorian 			isc_buffer_usedregion(&target, &r);
2965185a700Sflorian 			if (no_rdata)
2975185a700Sflorian 				printf(";%.*s", (int)r.length,
2985185a700Sflorian 				       (char *)r.base);
2995185a700Sflorian 			else
3005185a700Sflorian 				printf("%.*s", (int)r.length, (char *)r.base);
3015185a700Sflorian 		}
3025185a700Sflorian 
3035185a700Sflorian 		result = dns_message_nextname(msg, sectionid);
3045185a700Sflorian 		if (result == ISC_R_NOMORE)
3055185a700Sflorian 			break;
3065185a700Sflorian 		else if (result != ISC_R_SUCCESS)
3075185a700Sflorian 			return (result);
3085185a700Sflorian 	}
3095185a700Sflorian 
3105185a700Sflorian 	return (ISC_R_SUCCESS);
3115185a700Sflorian }
3125185a700Sflorian 
3135185a700Sflorian static isc_result_t
printrdata(dns_message_t * msg,dns_rdataset_t * rdataset,dns_name_t * owner,const char * set_name,int headers)3145185a700Sflorian printrdata(dns_message_t *msg, dns_rdataset_t *rdataset, dns_name_t *owner,
3151fb015a8Sflorian 	   const char *set_name, int headers)
3165185a700Sflorian {
3175185a700Sflorian 	isc_buffer_t target;
3185185a700Sflorian 	isc_result_t result;
3195185a700Sflorian 	isc_region_t r;
3205185a700Sflorian 	char tbuf[4096];
3215185a700Sflorian 
3225185a700Sflorian 	UNUSED(msg);
3235185a700Sflorian 	if (headers)
3245185a700Sflorian 		printf(";; %s SECTION:\n", set_name);
3255185a700Sflorian 
3265185a700Sflorian 	isc_buffer_init(&target, tbuf, sizeof(tbuf));
3275185a700Sflorian 
3281fb015a8Sflorian 	result = dns_rdataset_totext(rdataset, owner, 0, 0,
3295185a700Sflorian 				     &target);
3305185a700Sflorian 	if (result != ISC_R_SUCCESS)
3315185a700Sflorian 		return (result);
3325185a700Sflorian 	isc_buffer_usedregion(&target, &r);
3335185a700Sflorian 	printf("%.*s", (int)r.length, (char *)r.base);
3345185a700Sflorian 
3355185a700Sflorian 	return (ISC_R_SUCCESS);
3365185a700Sflorian }
3375185a700Sflorian 
3385185a700Sflorian static void
chase_cnamechain(dns_message_t * msg,dns_name_t * qname)3395185a700Sflorian chase_cnamechain(dns_message_t *msg, dns_name_t *qname) {
3405185a700Sflorian 	isc_result_t result;
3415185a700Sflorian 	dns_rdataset_t *rdataset;
3425185a700Sflorian 	dns_rdata_cname_t cname;
3435185a700Sflorian 	dns_rdata_t rdata = DNS_RDATA_INIT;
3445185a700Sflorian 	unsigned int i = msg->counts[DNS_SECTION_ANSWER];
3455185a700Sflorian 
3465185a700Sflorian 	while (i-- > 0) {
3475185a700Sflorian 		rdataset = NULL;
3485185a700Sflorian 		result = dns_message_findname(msg, DNS_SECTION_ANSWER, qname,
3495185a700Sflorian 					      dns_rdatatype_cname, 0, NULL,
3505185a700Sflorian 					      &rdataset);
3515185a700Sflorian 		if (result != ISC_R_SUCCESS)
3525185a700Sflorian 			return;
3535185a700Sflorian 		result = dns_rdataset_first(rdataset);
3545185a700Sflorian 		check_result(result, "dns_rdataset_first");
3555185a700Sflorian 		dns_rdata_reset(&rdata);
3565185a700Sflorian 		dns_rdataset_current(rdataset, &rdata);
357ee21177aSflorian 		result = dns_rdata_tostruct_cname(&rdata, &cname);
358ee21177aSflorian 		check_result(result, "dns_rdata_tostruct_cname");
3595185a700Sflorian 		dns_name_copy(&cname.cname, qname, NULL);
360a0b66ce4Sflorian 		dns_rdata_freestruct_cname(&cname);
3615185a700Sflorian 	}
3625185a700Sflorian }
3635185a700Sflorian 
3645185a700Sflorian static isc_result_t
printmessage(dig_query_t * query,dns_message_t * msg,int headers)3651fb015a8Sflorian printmessage(dig_query_t *query, dns_message_t *msg, int headers) {
3661fb015a8Sflorian 	int did_flag = 0;
3675185a700Sflorian 	dns_rdataset_t *opt, *tsig = NULL;
3685185a700Sflorian 	dns_name_t *tsigname;
3695185a700Sflorian 	isc_result_t result = ISC_R_SUCCESS;
3705185a700Sflorian 	int force_error;
3715185a700Sflorian 
3725185a700Sflorian 	UNUSED(headers);
3735185a700Sflorian 
3745185a700Sflorian 	/*
3755185a700Sflorian 	 * We get called multiple times.
3765185a700Sflorian 	 * Preserve any existing error status.
3775185a700Sflorian 	 */
3785185a700Sflorian 	force_error = (seen_error == 1) ? 1 : 0;
3795185a700Sflorian 	seen_error = 1;
3805185a700Sflorian 	if (listed_server && !printed_server) {
3815185a700Sflorian 		char sockstr[ISC_SOCKADDR_FORMATSIZE];
3825185a700Sflorian 
3835185a700Sflorian 		printf("Using domain server:\n");
3845185a700Sflorian 		printf("Name: %s\n", query->userarg);
3855185a700Sflorian 		isc_sockaddr_format(&query->sockaddr, sockstr,
3865185a700Sflorian 				    sizeof(sockstr));
3875185a700Sflorian 		printf("Address: %s\n", sockstr);
3885185a700Sflorian 		printf("Aliases: \n\n");
3891fb015a8Sflorian 		printed_server = 1;
3905185a700Sflorian 	}
3915185a700Sflorian 
3925185a700Sflorian 	if (msg->rcode != 0) {
3935185a700Sflorian 		char namestr[DNS_NAME_FORMATSIZE];
3945185a700Sflorian 		dns_name_format(query->lookup->name, namestr, sizeof(namestr));
3955185a700Sflorian 
3965185a700Sflorian 		if (query->lookup->identify_previous_line)
3975185a700Sflorian 			printf("Nameserver %s:\n\t%s not found: %d(%s)\n",
3985185a700Sflorian 			       query->servname,
3995185a700Sflorian 			       (msg->rcode != dns_rcode_nxdomain) ? namestr :
4005185a700Sflorian 			       query->lookup->textname, msg->rcode,
4015185a700Sflorian 			       rcode_totext(msg->rcode));
4025185a700Sflorian 		else
4035185a700Sflorian 			printf("Host %s not found: %d(%s)\n",
4045185a700Sflorian 			       (msg->rcode != dns_rcode_nxdomain) ? namestr :
4055185a700Sflorian 			       query->lookup->textname, msg->rcode,
4065185a700Sflorian 			       rcode_totext(msg->rcode));
4075185a700Sflorian 		return (ISC_R_SUCCESS);
4085185a700Sflorian 	}
4095185a700Sflorian 
4105185a700Sflorian 	if (default_lookups && query->lookup->rdtype == dns_rdatatype_a) {
4115185a700Sflorian 		char namestr[DNS_NAME_FORMATSIZE];
4125185a700Sflorian 		dig_lookup_t *lookup;
4135185a700Sflorian 		dns_fixedname_t fixed;
4145185a700Sflorian 		dns_name_t *name;
4155185a700Sflorian 
4165185a700Sflorian 		/* Add AAAA and MX lookups. */
4175185a700Sflorian 		dns_fixedname_init(&fixed);
4185185a700Sflorian 		name = dns_fixedname_name(&fixed);
4195185a700Sflorian 		dns_name_copy(query->lookup->name, name, NULL);
4205185a700Sflorian 		chase_cnamechain(msg, name);
4215185a700Sflorian 		dns_name_format(name, namestr, sizeof(namestr));
4221fb015a8Sflorian 		lookup = clone_lookup(query->lookup, 0);
4235185a700Sflorian 		if (lookup != NULL) {
4245185a700Sflorian 			strlcpy(lookup->textname, namestr,
4255185a700Sflorian 				sizeof(lookup->textname));
4265185a700Sflorian 			lookup->rdtype = dns_rdatatype_aaaa;
4271fb015a8Sflorian 			lookup->rdtypeset = 1;
4285185a700Sflorian 			lookup->origin = NULL;
4295185a700Sflorian 			lookup->retries = tries;
4305185a700Sflorian 			ISC_LIST_APPEND(lookup_list, lookup, link);
4315185a700Sflorian 		}
4321fb015a8Sflorian 		lookup = clone_lookup(query->lookup, 0);
4335185a700Sflorian 		if (lookup != NULL) {
4345185a700Sflorian 			strlcpy(lookup->textname, namestr,
4355185a700Sflorian 				sizeof(lookup->textname));
4365185a700Sflorian 			lookup->rdtype = dns_rdatatype_mx;
4371fb015a8Sflorian 			lookup->rdtypeset = 1;
4385185a700Sflorian 			lookup->origin = NULL;
4395185a700Sflorian 			lookup->retries = tries;
4405185a700Sflorian 			ISC_LIST_APPEND(lookup_list, lookup, link);
4415185a700Sflorian 		}
4425185a700Sflorian 	}
4435185a700Sflorian 
4445185a700Sflorian 	if (!short_form) {
4455185a700Sflorian 		printf(";; ->>HEADER<<- opcode: %s, status: %s, id: %u\n",
4465185a700Sflorian 		       opcodetext[msg->opcode], rcode_totext(msg->rcode),
4475185a700Sflorian 		       msg->id);
4485185a700Sflorian 		printf(";; flags: ");
4495185a700Sflorian 		if ((msg->flags & DNS_MESSAGEFLAG_QR) != 0) {
4505185a700Sflorian 			printf("qr");
4511fb015a8Sflorian 			did_flag = 1;
4525185a700Sflorian 		}
4535185a700Sflorian 		if ((msg->flags & DNS_MESSAGEFLAG_AA) != 0) {
4545185a700Sflorian 			printf("%saa", did_flag ? " " : "");
4551fb015a8Sflorian 			did_flag = 1;
4565185a700Sflorian 		}
4575185a700Sflorian 		if ((msg->flags & DNS_MESSAGEFLAG_TC) != 0) {
4585185a700Sflorian 			printf("%stc", did_flag ? " " : "");
4591fb015a8Sflorian 			did_flag = 1;
4605185a700Sflorian 		}
4615185a700Sflorian 		if ((msg->flags & DNS_MESSAGEFLAG_RD) != 0) {
4625185a700Sflorian 			printf("%srd", did_flag ? " " : "");
4631fb015a8Sflorian 			did_flag = 1;
4645185a700Sflorian 		}
4655185a700Sflorian 		if ((msg->flags & DNS_MESSAGEFLAG_RA) != 0) {
4665185a700Sflorian 			printf("%sra", did_flag ? " " : "");
4671fb015a8Sflorian 			did_flag = 1;
4685185a700Sflorian 		}
4695185a700Sflorian 		if ((msg->flags & DNS_MESSAGEFLAG_AD) != 0) {
4705185a700Sflorian 			printf("%sad", did_flag ? " " : "");
4711fb015a8Sflorian 			did_flag = 1;
4725185a700Sflorian 		}
4735185a700Sflorian 		if ((msg->flags & DNS_MESSAGEFLAG_CD) != 0) {
4745185a700Sflorian 			printf("%scd", did_flag ? " " : "");
4751fb015a8Sflorian 			did_flag = 1;
4765185a700Sflorian 			POST(did_flag);
4775185a700Sflorian 		}
4785185a700Sflorian 		printf("; QUERY: %u, ANSWER: %u, "
4795185a700Sflorian 		       "AUTHORITY: %u, ADDITIONAL: %u\n",
4805185a700Sflorian 		       msg->counts[DNS_SECTION_QUESTION],
4815185a700Sflorian 		       msg->counts[DNS_SECTION_ANSWER],
4825185a700Sflorian 		       msg->counts[DNS_SECTION_AUTHORITY],
4835185a700Sflorian 		       msg->counts[DNS_SECTION_ADDITIONAL]);
4845185a700Sflorian 		opt = dns_message_getopt(msg);
4855185a700Sflorian 		if (opt != NULL)
4865185a700Sflorian 			printf(";; EDNS: version: %u, udp=%u\n",
4875185a700Sflorian 			       (unsigned int)((opt->ttl & 0x00ff0000) >> 16),
4885185a700Sflorian 			       (unsigned int)opt->rdclass);
4895185a700Sflorian 		tsigname = NULL;
4905185a700Sflorian 		tsig = dns_message_gettsig(msg, &tsigname);
4915185a700Sflorian 		if (tsig != NULL)
4925185a700Sflorian 			printf(";; PSEUDOSECTIONS: TSIG\n");
4935185a700Sflorian 	}
4945185a700Sflorian 	if (! ISC_LIST_EMPTY(msg->sections[DNS_SECTION_QUESTION]) &&
4955185a700Sflorian 	    !short_form) {
4965185a700Sflorian 		printf("\n");
4975185a700Sflorian 		result = printsection(msg, DNS_SECTION_QUESTION, "QUESTION",
4981fb015a8Sflorian 				      1, query);
4995185a700Sflorian 		if (result != ISC_R_SUCCESS)
5005185a700Sflorian 			return (result);
5015185a700Sflorian 	}
5025185a700Sflorian 	if (! ISC_LIST_EMPTY(msg->sections[DNS_SECTION_ANSWER])) {
5035185a700Sflorian 		if (!short_form)
5045185a700Sflorian 			printf("\n");
5055185a700Sflorian 		result = printsection(msg, DNS_SECTION_ANSWER, "ANSWER",
5061fb015a8Sflorian 				      !short_form, query);
5075185a700Sflorian 		if (result != ISC_R_SUCCESS)
5085185a700Sflorian 			return (result);
5095185a700Sflorian 	}
5105185a700Sflorian 
5115185a700Sflorian 	if (! ISC_LIST_EMPTY(msg->sections[DNS_SECTION_AUTHORITY]) &&
5125185a700Sflorian 	    !short_form) {
5135185a700Sflorian 		printf("\n");
5145185a700Sflorian 		result = printsection(msg, DNS_SECTION_AUTHORITY, "AUTHORITY",
5151fb015a8Sflorian 				      1, query);
5165185a700Sflorian 		if (result != ISC_R_SUCCESS)
5175185a700Sflorian 			return (result);
5185185a700Sflorian 	}
5195185a700Sflorian 	if (! ISC_LIST_EMPTY(msg->sections[DNS_SECTION_ADDITIONAL]) &&
5205185a700Sflorian 	    !short_form) {
5215185a700Sflorian 		printf("\n");
5225185a700Sflorian 		result = printsection(msg, DNS_SECTION_ADDITIONAL,
5231fb015a8Sflorian 				      "ADDITIONAL", 1, query);
5245185a700Sflorian 		if (result != ISC_R_SUCCESS)
5255185a700Sflorian 			return (result);
5265185a700Sflorian 	}
5275185a700Sflorian 	if ((tsig != NULL) && !short_form) {
5285185a700Sflorian 		printf("\n");
5295185a700Sflorian 		result = printrdata(msg, tsig, tsigname,
5301fb015a8Sflorian 				    "PSEUDOSECTION TSIG", 1);
5315185a700Sflorian 		if (result != ISC_R_SUCCESS)
5325185a700Sflorian 			return (result);
5335185a700Sflorian 	}
5345185a700Sflorian 	if (!short_form)
5355185a700Sflorian 		printf("\n");
5365185a700Sflorian 
5375185a700Sflorian 	if (short_form && !default_lookups &&
5385185a700Sflorian 	    ISC_LIST_EMPTY(msg->sections[DNS_SECTION_ANSWER])) {
5395185a700Sflorian 		char namestr[DNS_NAME_FORMATSIZE];
5405185a700Sflorian 		char typestr[DNS_RDATATYPE_FORMATSIZE];
5415185a700Sflorian 		dns_name_format(query->lookup->name, namestr, sizeof(namestr));
5425185a700Sflorian 		dns_rdatatype_format(query->lookup->rdtype, typestr,
5435185a700Sflorian 				     sizeof(typestr));
5445185a700Sflorian 		printf("%s has no %s record\n", namestr, typestr);
5455185a700Sflorian 	}
5465185a700Sflorian 	seen_error = force_error;
5475185a700Sflorian 	return (result);
5485185a700Sflorian }
5495185a700Sflorian 
5505185a700Sflorian static const char * optstring = "46ac:dilnrst:vVwCDN:R:TW:";
5515185a700Sflorian 
5525185a700Sflorian /*% version */
5535185a700Sflorian static void
version(void)5545185a700Sflorian version(void) {
5555185a700Sflorian 	fputs("host " VERSION "\n", stderr);
5565185a700Sflorian }
5575185a700Sflorian 
5585185a700Sflorian static void
pre_parse_args(int argc,char ** argv)5595185a700Sflorian pre_parse_args(int argc, char **argv) {
5605185a700Sflorian 	int c;
5615185a700Sflorian 
5625185a700Sflorian 	while ((c = getopt(argc, argv, optstring)) != -1) {
5635185a700Sflorian 		switch (c) {
5645185a700Sflorian 		case '4':
5655185a700Sflorian 			if (ipv6only)
5665185a700Sflorian 				fatal("only one of -4 and -6 allowed");
5671fb015a8Sflorian 			ipv4only = 1;
5685185a700Sflorian 			break;
5695185a700Sflorian 		case '6':
5705185a700Sflorian 			if (ipv4only)
5715185a700Sflorian 				fatal("only one of -4 and -6 allowed");
5721fb015a8Sflorian 			ipv6only = 1;
5735185a700Sflorian 			break;
5745185a700Sflorian 		case 'a': break;
5755185a700Sflorian 		case 'c': break;
5765185a700Sflorian 		case 'd': break;
5775185a700Sflorian 		case 'i': break;
5785185a700Sflorian 		case 'l': break;
5795185a700Sflorian 		case 'n': break;
5805185a700Sflorian 		case 'r': break;
5815185a700Sflorian 		case 's': break;
5825185a700Sflorian 		case 't': break;
5835185a700Sflorian 		case 'v': break;
5845185a700Sflorian 		case 'V':
5855185a700Sflorian 			  version();
5865185a700Sflorian 			  exit(0);
5875185a700Sflorian 			  break;
5885185a700Sflorian 		case 'w': break;
5895185a700Sflorian 		case 'C': break;
5905185a700Sflorian 		case 'D':
5915185a700Sflorian 			if (debugging)
5921fb015a8Sflorian 				debugtiming = 1;
5931fb015a8Sflorian 			debugging = 1;
5945185a700Sflorian 			break;
5955185a700Sflorian 		case 'N': break;
5965185a700Sflorian 		case 'R': break;
5975185a700Sflorian 		case 'T': break;
5985185a700Sflorian 		case 'W': break;
5995185a700Sflorian 		default:
6005185a700Sflorian 			show_usage();
6015185a700Sflorian 		}
6025185a700Sflorian 	}
6035185a700Sflorian 	optind = 1;
6045185a700Sflorian 	optreset = 1;
6055185a700Sflorian }
6065185a700Sflorian 
6075185a700Sflorian static void
parse_args(int argc,char ** argv)6085185a700Sflorian parse_args(int argc, char **argv) {
6095185a700Sflorian 	char hostname[MXNAME];
6105185a700Sflorian 	dig_lookup_t *lookup;
6115185a700Sflorian 	int c;
6125185a700Sflorian 	char store[MXNAME];
6135185a700Sflorian 	isc_textregion_t tr;
6145185a700Sflorian 	isc_result_t result = ISC_R_SUCCESS;
6155185a700Sflorian 	dns_rdatatype_t rdtype;
6165185a700Sflorian 	dns_rdataclass_t rdclass;
6175185a700Sflorian 	uint32_t serial = 0;
6185185a700Sflorian 	const char *errstr;
6195185a700Sflorian 
6205185a700Sflorian 	lookup = make_empty_lookup();
6215185a700Sflorian 
6221fb015a8Sflorian 	lookup->servfail_stops = 0;
6231fb015a8Sflorian 	lookup->comments = 0;
6245185a700Sflorian 
6255185a700Sflorian 	while ((c = getopt(argc, argv, optstring)) != -1) {
6265185a700Sflorian 		switch (c) {
6275185a700Sflorian 		case 'l':
6281fb015a8Sflorian 			lookup->tcp_mode = 1;
6295185a700Sflorian 			lookup->rdtype = dns_rdatatype_axfr;
6301fb015a8Sflorian 			lookup->rdtypeset = 1;
6315185a700Sflorian 			fatalexit = 3;
6325185a700Sflorian 			break;
6335185a700Sflorian 		case 'v':
6345185a700Sflorian 		case 'd':
6351fb015a8Sflorian 			short_form = 0;
6365185a700Sflorian 			break;
6375185a700Sflorian 		case 'r':
6381fb015a8Sflorian 			lookup->recurse = 0;
6395185a700Sflorian 			break;
6405185a700Sflorian 		case 't':
6415185a700Sflorian 			if (strncasecmp(optarg,	"ixfr=", 5) == 0) {
6425185a700Sflorian 				rdtype = dns_rdatatype_ixfr;
6435185a700Sflorian 				/* XXXMPA add error checking */
6445185a700Sflorian 				serial = strtoul(optarg + 5,
6455185a700Sflorian 						 NULL, 10);
6465185a700Sflorian 				result = ISC_R_SUCCESS;
6475185a700Sflorian 			} else {
6485185a700Sflorian 				tr.base = optarg;
6495185a700Sflorian 				tr.length = strlen(optarg);
6505185a700Sflorian 				result = dns_rdatatype_fromtext(&rdtype,
6515185a700Sflorian 						   (isc_textregion_t *)&tr);
6525185a700Sflorian 			}
6535185a700Sflorian 
6545185a700Sflorian 			if (result != ISC_R_SUCCESS) {
6555185a700Sflorian 				fatalexit = 2;
6565185a700Sflorian 				fatal("invalid type: %s\n", optarg);
6575185a700Sflorian 			}
6585185a700Sflorian 			if (!lookup->rdtypeset ||
6595185a700Sflorian 			    lookup->rdtype != dns_rdatatype_axfr)
6605185a700Sflorian 				lookup->rdtype = rdtype;
6611fb015a8Sflorian 			lookup->rdtypeset = 1;
6625185a700Sflorian 			if (rdtype == dns_rdatatype_axfr) {
6635185a700Sflorian 				/* -l -t any -v */
6645185a700Sflorian 				list_type = dns_rdatatype_any;
6651fb015a8Sflorian 				short_form = 0;
6661fb015a8Sflorian 				lookup->tcp_mode = 1;
6675185a700Sflorian 			} else if (rdtype == dns_rdatatype_ixfr) {
6685185a700Sflorian 				lookup->ixfr_serial = serial;
6691fb015a8Sflorian 				lookup->tcp_mode = 1;
6705185a700Sflorian 				list_type = rdtype;
6715185a700Sflorian 			} else
6725185a700Sflorian 				list_type = rdtype;
6731fb015a8Sflorian 			list_addresses = 0;
6741fb015a8Sflorian 			default_lookups = 0;
6755185a700Sflorian 			break;
6765185a700Sflorian 		case 'c':
6775185a700Sflorian 			tr.base = optarg;
6785185a700Sflorian 			tr.length = strlen(optarg);
6795185a700Sflorian 			result = dns_rdataclass_fromtext(&rdclass,
6805185a700Sflorian 						   (isc_textregion_t *)&tr);
6815185a700Sflorian 
6825185a700Sflorian 			if (result != ISC_R_SUCCESS) {
6835185a700Sflorian 				fatalexit = 2;
6845185a700Sflorian 				fatal("invalid class: %s\n", optarg);
6855185a700Sflorian 			} else {
6865185a700Sflorian 				lookup->rdclass = rdclass;
6871fb015a8Sflorian 				lookup->rdclassset = 1;
6885185a700Sflorian 			}
6891fb015a8Sflorian 			default_lookups = 0;
6905185a700Sflorian 			break;
6915185a700Sflorian 		case 'a':
6925185a700Sflorian 			if (!lookup->rdtypeset ||
6935185a700Sflorian 			    lookup->rdtype != dns_rdatatype_axfr)
6945185a700Sflorian 				lookup->rdtype = dns_rdatatype_any;
6955185a700Sflorian 			list_type = dns_rdatatype_any;
6961fb015a8Sflorian 			list_addresses = 0;
6971fb015a8Sflorian 			lookup->rdtypeset = 1;
6981fb015a8Sflorian 			short_form = 0;
6991fb015a8Sflorian 			default_lookups = 0;
7005185a700Sflorian 			break;
7015185a700Sflorian 		case 'i':
7021fb015a8Sflorian 			lookup->ip6_int = 1;
7035185a700Sflorian 			break;
7045185a700Sflorian 		case 'n':
7055185a700Sflorian 			/* deprecated */
7065185a700Sflorian 			break;
7075185a700Sflorian 		case 'm':
7085185a700Sflorian 			/* Handled by pre_parse_args(). */
7095185a700Sflorian 			break;
7105185a700Sflorian 		case 'w':
7115185a700Sflorian 			/*
7125185a700Sflorian 			 * The timer routines are coded such that
7135185a700Sflorian 			 * timeout==MAXINT doesn't enable the timer
7145185a700Sflorian 			 */
7155185a700Sflorian 			timeout = INT_MAX;
7165185a700Sflorian 			break;
7175185a700Sflorian 		case 'W':
7185185a700Sflorian 			timeout = strtonum(optarg, 0, INT_MAX, &errstr);
7195185a700Sflorian 			if (errstr != NULL)
7205185a700Sflorian 				errx(1, "timeout is %s: %s", errstr, optarg);
7215185a700Sflorian 			if (timeout < 1)
7225185a700Sflorian 				timeout = 1;
7235185a700Sflorian 			break;
7245185a700Sflorian 		case 'R':
7255185a700Sflorian 			tries = strtonum(optarg, INT_MIN, INT_MAX - 1, &errstr);
7265185a700Sflorian 			if (errstr != NULL)
7275185a700Sflorian 				errx(1, "retries is %s: %s", errstr, optarg);
7285185a700Sflorian 			tries++;
7295185a700Sflorian 			if (tries < 2)
7305185a700Sflorian 				tries = 2;
7315185a700Sflorian 			break;
7325185a700Sflorian 		case 'T':
7331fb015a8Sflorian 			lookup->tcp_mode = 1;
7345185a700Sflorian 			break;
7355185a700Sflorian 		case 'C':
7365185a700Sflorian 			debug("showing all SOAs");
7375185a700Sflorian 			lookup->rdtype = dns_rdatatype_ns;
7381fb015a8Sflorian 			lookup->rdtypeset = 1;
7395185a700Sflorian 			lookup->rdclass = dns_rdataclass_in;
7401fb015a8Sflorian 			lookup->rdclassset = 1;
7411fb015a8Sflorian 			lookup->ns_search_only = 1;
7421fb015a8Sflorian 			lookup->trace_root = 1;
7431fb015a8Sflorian 			lookup->identify_previous_line = 1;
7441fb015a8Sflorian 			default_lookups = 0;
7455185a700Sflorian 			break;
7465185a700Sflorian 		case 'N':
7475185a700Sflorian 			debug("setting NDOTS to %s", optarg);
7485185a700Sflorian 			ndots = strtonum(optarg, 0, INT_MAX, &errstr);
7495185a700Sflorian 			if (errstr != NULL)
7505185a700Sflorian 				errx(1, "ndots is %s: %s", errstr, optarg);
7515185a700Sflorian 			break;
7525185a700Sflorian 		case 'D':
7535185a700Sflorian 			/* Handled by pre_parse_args(). */
7545185a700Sflorian 			break;
7555185a700Sflorian 		case '4':
7565185a700Sflorian 			/* Handled by pre_parse_args(). */
7575185a700Sflorian 			break;
7585185a700Sflorian 		case '6':
7595185a700Sflorian 			/* Handled by pre_parse_args(). */
7605185a700Sflorian 			break;
7615185a700Sflorian 		case 's':
7621fb015a8Sflorian 			lookup->servfail_stops = 1;
7635185a700Sflorian 			break;
7645185a700Sflorian 		default:
7655185a700Sflorian 			show_usage();
7665185a700Sflorian 		}
7675185a700Sflorian 	}
7685185a700Sflorian 
7695185a700Sflorian 	lookup->retries = tries;
7705185a700Sflorian 
7715185a700Sflorian 	argc -= optind;
7725185a700Sflorian 	argv += optind;
7735185a700Sflorian 
7745185a700Sflorian 	if (argc == 0)
7755185a700Sflorian 		show_usage();
7765185a700Sflorian 
777f5ba66e4Sflorian 	strlcpy(hostname, argv[0], sizeof(hostname));
7785185a700Sflorian 
779f5ba66e4Sflorian 	if (argc >= 2) {
780aebd9aa6Sderaadt 		isc_result_t res;
781aebd9aa6Sderaadt 
782aebd9aa6Sderaadt 		if ((res = set_nameserver(argv[1])))
783aebd9aa6Sderaadt 			fatal("couldn't get address for '%s': %s",
784aebd9aa6Sderaadt 			    argv[1], isc_result_totext(res));
7855185a700Sflorian 		debug("server is %s", *argv + 1);
7861fb015a8Sflorian 		listed_server = 1;
7875185a700Sflorian 	} else
7881fb015a8Sflorian 		check_ra = 1;
7895185a700Sflorian 
7901fb015a8Sflorian 	lookup->pending = 0;
7915185a700Sflorian 	if (get_reverse(store, sizeof(store), hostname,
7921fb015a8Sflorian 			lookup->ip6_int, 1) == ISC_R_SUCCESS) {
7935185a700Sflorian 		strlcpy(lookup->textname, store, sizeof(lookup->textname));
7945185a700Sflorian 		lookup->rdtype = dns_rdatatype_ptr;
7951fb015a8Sflorian 		lookup->rdtypeset = 1;
7961fb015a8Sflorian 		default_lookups = 0;
7975185a700Sflorian 	} else {
7985185a700Sflorian 		strlcpy(lookup->textname, hostname, sizeof(lookup->textname));
7991fb015a8Sflorian 		usesearch = 1;
8005185a700Sflorian 	}
8011fb015a8Sflorian 	lookup->new_search = 1;
8025185a700Sflorian 	ISC_LIST_APPEND(lookup_list, lookup, link);
8035185a700Sflorian }
8045185a700Sflorian 
8055185a700Sflorian int
host_main(int argc,char ** argv)8065185a700Sflorian host_main(int argc, char **argv) {
8075185a700Sflorian 	isc_result_t result;
8085185a700Sflorian 
8095185a700Sflorian 	tries = 2;
8105185a700Sflorian 
8115185a700Sflorian 	ISC_LIST_INIT(lookup_list);
8125185a700Sflorian 	ISC_LIST_INIT(server_list);
813927deb69Sflorian 	ISC_LIST_INIT(root_hints_server_list);
8145185a700Sflorian 	ISC_LIST_INIT(search_list);
8155185a700Sflorian 
8165185a700Sflorian 	fatalexit = 1;
8175185a700Sflorian 
8185185a700Sflorian 	/* setup dighost callbacks */
8195185a700Sflorian 	dighost_printmessage = printmessage;
8205185a700Sflorian 	dighost_received = received;
8215185a700Sflorian 	dighost_trying = trying;
8225185a700Sflorian 	dighost_shutdown = host_shutdown;
8235185a700Sflorian 
8245185a700Sflorian 	debug("main()");
8255185a700Sflorian 	progname = argv[0];
8265185a700Sflorian 	pre_parse_args(argc, argv);
8275185a700Sflorian 	result = isc_app_start();
8285185a700Sflorian 	check_result(result, "isc_app_start");
8295185a700Sflorian 
8305185a700Sflorian 	if (pledge("stdio rpath inet dns", NULL) == -1) {
8315185a700Sflorian 		perror("pledge");
8325185a700Sflorian 		exit(1);
8335185a700Sflorian 	}
8345185a700Sflorian 
8355185a700Sflorian 	setup_libs();
8365185a700Sflorian 
8375185a700Sflorian 	if (pledge("stdio inet dns", NULL) == -1) {
8385185a700Sflorian 		perror("pledge");
8395185a700Sflorian 		exit(1);
8405185a700Sflorian 	}
8415185a700Sflorian 
8425185a700Sflorian 	parse_args(argc, argv);
8435185a700Sflorian 	setup_system(ipv4only, ipv6only);
8445185a700Sflorian 	result = isc_app_onrun(global_task, onrun_callback, NULL);
8455185a700Sflorian 	check_result(result, "isc_app_onrun");
8465185a700Sflorian 	isc_app_run();
8475185a700Sflorian 	cancel_all();
8485185a700Sflorian 	destroy_libs();
8495185a700Sflorian 	return ((seen_error == 0) ? 0 : 1);
8505185a700Sflorian }
851