xref: /freebsd/contrib/unbound/smallapp/unbound-host.c (revision b7579f77d18196a58ff700756c84dc9a302a7f67)
1*b7579f77SDag-Erling Smørgrav /*
2*b7579f77SDag-Erling Smørgrav  * checkconf/unbound-host.c - replacement for host that supports validation.
3*b7579f77SDag-Erling Smørgrav  *
4*b7579f77SDag-Erling Smørgrav  * Copyright (c) 2007, NLnet Labs. All rights reserved.
5*b7579f77SDag-Erling Smørgrav  *
6*b7579f77SDag-Erling Smørgrav  * This software is open source.
7*b7579f77SDag-Erling Smørgrav  *
8*b7579f77SDag-Erling Smørgrav  * Redistribution and use in source and binary forms, with or without
9*b7579f77SDag-Erling Smørgrav  * modification, are permitted provided that the following conditions
10*b7579f77SDag-Erling Smørgrav  * are met:
11*b7579f77SDag-Erling Smørgrav  *
12*b7579f77SDag-Erling Smørgrav  * Redistributions of source code must retain the above copyright notice,
13*b7579f77SDag-Erling Smørgrav  * this list of conditions and the following disclaimer.
14*b7579f77SDag-Erling Smørgrav  *
15*b7579f77SDag-Erling Smørgrav  * Redistributions in binary form must reproduce the above copyright notice,
16*b7579f77SDag-Erling Smørgrav  * this list of conditions and the following disclaimer in the documentation
17*b7579f77SDag-Erling Smørgrav  * and/or other materials provided with the distribution.
18*b7579f77SDag-Erling Smørgrav  *
19*b7579f77SDag-Erling Smørgrav  * Neither the name of the NLNET LABS nor the names of its contributors may
20*b7579f77SDag-Erling Smørgrav  * be used to endorse or promote products derived from this software without
21*b7579f77SDag-Erling Smørgrav  * specific prior written permission.
22*b7579f77SDag-Erling Smørgrav  *
23*b7579f77SDag-Erling Smørgrav  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
24*b7579f77SDag-Erling Smørgrav  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
25*b7579f77SDag-Erling Smørgrav  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
26*b7579f77SDag-Erling Smørgrav  * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE
27*b7579f77SDag-Erling Smørgrav  * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
28*b7579f77SDag-Erling Smørgrav  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
29*b7579f77SDag-Erling Smørgrav  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
30*b7579f77SDag-Erling Smørgrav  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
31*b7579f77SDag-Erling Smørgrav  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
32*b7579f77SDag-Erling Smørgrav  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
33*b7579f77SDag-Erling Smørgrav  * POSSIBILITY OF SUCH DAMAGE.
34*b7579f77SDag-Erling Smørgrav  */
35*b7579f77SDag-Erling Smørgrav 
36*b7579f77SDag-Erling Smørgrav /**
37*b7579f77SDag-Erling Smørgrav  * \file
38*b7579f77SDag-Erling Smørgrav  *
39*b7579f77SDag-Erling Smørgrav  * This file performs functionality like 'host', and also supports validation.
40*b7579f77SDag-Erling Smørgrav  * It uses the libunbound library.
41*b7579f77SDag-Erling Smørgrav  */
42*b7579f77SDag-Erling Smørgrav 
43*b7579f77SDag-Erling Smørgrav #include "config.h"
44*b7579f77SDag-Erling Smørgrav #ifdef HAVE_GETOPT_H
45*b7579f77SDag-Erling Smørgrav #include <getopt.h>
46*b7579f77SDag-Erling Smørgrav #endif
47*b7579f77SDag-Erling Smørgrav /* remove alloc checks, not in this part of the code */
48*b7579f77SDag-Erling Smørgrav #ifdef UNBOUND_ALLOC_STATS
49*b7579f77SDag-Erling Smørgrav #undef malloc
50*b7579f77SDag-Erling Smørgrav #undef calloc
51*b7579f77SDag-Erling Smørgrav #undef free
52*b7579f77SDag-Erling Smørgrav #undef realloc
53*b7579f77SDag-Erling Smørgrav #endif
54*b7579f77SDag-Erling Smørgrav #ifdef UNBOUND_ALLOC_LITE
55*b7579f77SDag-Erling Smørgrav #undef malloc
56*b7579f77SDag-Erling Smørgrav #undef calloc
57*b7579f77SDag-Erling Smørgrav #undef free
58*b7579f77SDag-Erling Smørgrav #undef realloc
59*b7579f77SDag-Erling Smørgrav #undef strdup
60*b7579f77SDag-Erling Smørgrav #define unbound_lite_wrapstr(s) s
61*b7579f77SDag-Erling Smørgrav #endif
62*b7579f77SDag-Erling Smørgrav #include "libunbound/unbound.h"
63*b7579f77SDag-Erling Smørgrav #include <ldns/ldns.h>
64*b7579f77SDag-Erling Smørgrav 
65*b7579f77SDag-Erling Smørgrav /** verbosity for unbound-host app */
66*b7579f77SDag-Erling Smørgrav static int verb = 0;
67*b7579f77SDag-Erling Smørgrav 
68*b7579f77SDag-Erling Smørgrav /** Give unbound-host usage, and exit (1). */
69*b7579f77SDag-Erling Smørgrav static void
70*b7579f77SDag-Erling Smørgrav usage()
71*b7579f77SDag-Erling Smørgrav {
72*b7579f77SDag-Erling Smørgrav 	printf("Usage:	unbound-host [-vdhr46] [-c class] [-t type] hostname\n");
73*b7579f77SDag-Erling Smørgrav 	printf("                     [-y key] [-f keyfile] [-F namedkeyfile]\n");
74*b7579f77SDag-Erling Smørgrav 	printf("                     [-C configfile]\n");
75*b7579f77SDag-Erling Smørgrav 	printf("  Queries the DNS for information.\n");
76*b7579f77SDag-Erling Smørgrav 	printf("  The hostname is looked up for IP4, IP6 and mail.\n");
77*b7579f77SDag-Erling Smørgrav 	printf("  If an ip-address is given a reverse lookup is done.\n");
78*b7579f77SDag-Erling Smørgrav 	printf("  Use the -v option to see DNSSEC security information.\n");
79*b7579f77SDag-Erling Smørgrav 	printf("    -t type		what type to look for.\n");
80*b7579f77SDag-Erling Smørgrav 	printf("    -c class		what class to look for, if not class IN.\n");
81*b7579f77SDag-Erling Smørgrav 	printf("    -y 'keystring'	specify trust anchor, DS or DNSKEY, like\n");
82*b7579f77SDag-Erling Smørgrav 	printf("			-y 'example.com DS 31560 5 1 1CFED8478...'\n");
83*b7579f77SDag-Erling Smørgrav 	printf("    -f keyfile		read trust anchors from file, with lines as -y.\n");
84*b7579f77SDag-Erling Smørgrav 	printf("    -F keyfile		read named.conf-style trust anchors.\n");
85*b7579f77SDag-Erling Smørgrav 	printf("    -C config		use the specified unbound.conf (none read by default)\n");
86*b7579f77SDag-Erling Smørgrav 	printf("    -r			read forwarder information from /etc/resolv.conf\n");
87*b7579f77SDag-Erling Smørgrav 	printf("      			breaks validation if the fwder does not do DNSSEC.\n");
88*b7579f77SDag-Erling Smørgrav 	printf("    -v			be more verbose, shows nodata and security.\n");
89*b7579f77SDag-Erling Smørgrav 	printf("    -d			debug, traces the action, -d -d shows more.\n");
90*b7579f77SDag-Erling Smørgrav 	printf("    -4			use ipv4 network, avoid ipv6.\n");
91*b7579f77SDag-Erling Smørgrav 	printf("    -6			use ipv6 network, avoid ipv4.\n");
92*b7579f77SDag-Erling Smørgrav 	printf("    -h			show this usage help.\n");
93*b7579f77SDag-Erling Smørgrav 	printf("Version %s\n", PACKAGE_VERSION);
94*b7579f77SDag-Erling Smørgrav 	printf("BSD licensed, see LICENSE in source package for details.\n");
95*b7579f77SDag-Erling Smørgrav 	printf("Report bugs to %s\n", PACKAGE_BUGREPORT);
96*b7579f77SDag-Erling Smørgrav 	exit(1);
97*b7579f77SDag-Erling Smørgrav }
98*b7579f77SDag-Erling Smørgrav 
99*b7579f77SDag-Erling Smørgrav /** determine if str is ip4 and put into reverse lookup format */
100*b7579f77SDag-Erling Smørgrav static int
101*b7579f77SDag-Erling Smørgrav isip4(const char* nm, char** res)
102*b7579f77SDag-Erling Smørgrav {
103*b7579f77SDag-Erling Smørgrav 	struct in_addr addr;
104*b7579f77SDag-Erling Smørgrav 	/* ddd.ddd.ddd.ddd.in-addr.arpa. is less than 32 */
105*b7579f77SDag-Erling Smørgrav 	char buf[32];
106*b7579f77SDag-Erling Smørgrav 	if(inet_pton(AF_INET, nm, &addr) <= 0) {
107*b7579f77SDag-Erling Smørgrav 		return 0;
108*b7579f77SDag-Erling Smørgrav 	}
109*b7579f77SDag-Erling Smørgrav 	snprintf(buf, sizeof(buf), "%u.%u.%u.%u.in-addr.arpa",
110*b7579f77SDag-Erling Smørgrav 		(unsigned)((uint8_t*)&addr)[3], (unsigned)((uint8_t*)&addr)[2],
111*b7579f77SDag-Erling Smørgrav 		(unsigned)((uint8_t*)&addr)[1], (unsigned)((uint8_t*)&addr)[0]);
112*b7579f77SDag-Erling Smørgrav 	*res = strdup(buf);
113*b7579f77SDag-Erling Smørgrav 	return 1;
114*b7579f77SDag-Erling Smørgrav }
115*b7579f77SDag-Erling Smørgrav 
116*b7579f77SDag-Erling Smørgrav /** determine if str is ip6 and put into reverse lookup format */
117*b7579f77SDag-Erling Smørgrav static int
118*b7579f77SDag-Erling Smørgrav isip6(const char* nm, char** res)
119*b7579f77SDag-Erling Smørgrav {
120*b7579f77SDag-Erling Smørgrav 	struct in6_addr addr;
121*b7579f77SDag-Erling Smørgrav 	/* [nibble.]{32}.ip6.arpa. is less than 128 */
122*b7579f77SDag-Erling Smørgrav 	const char* hex = "0123456789abcdef";
123*b7579f77SDag-Erling Smørgrav 	char buf[128];
124*b7579f77SDag-Erling Smørgrav 	char *p;
125*b7579f77SDag-Erling Smørgrav 	int i;
126*b7579f77SDag-Erling Smørgrav 	if(inet_pton(AF_INET6, nm, &addr) <= 0) {
127*b7579f77SDag-Erling Smørgrav 		return 0;
128*b7579f77SDag-Erling Smørgrav 	}
129*b7579f77SDag-Erling Smørgrav 	p = buf;
130*b7579f77SDag-Erling Smørgrav 	for(i=15; i>=0; i--) {
131*b7579f77SDag-Erling Smørgrav 		uint8_t b = ((uint8_t*)&addr)[i];
132*b7579f77SDag-Erling Smørgrav 		*p++ = hex[ (b&0x0f) ];
133*b7579f77SDag-Erling Smørgrav 		*p++ = '.';
134*b7579f77SDag-Erling Smørgrav 		*p++ = hex[ (b&0xf0) >> 4 ];
135*b7579f77SDag-Erling Smørgrav 		*p++ = '.';
136*b7579f77SDag-Erling Smørgrav 	}
137*b7579f77SDag-Erling Smørgrav 	snprintf(buf+16*4, sizeof(buf)-16*4, "ip6.arpa");
138*b7579f77SDag-Erling Smørgrav 	*res = strdup(buf);
139*b7579f77SDag-Erling Smørgrav 	if(!*res) {
140*b7579f77SDag-Erling Smørgrav 		fprintf(stderr, "error: out of memory\n");
141*b7579f77SDag-Erling Smørgrav 		exit(1);
142*b7579f77SDag-Erling Smørgrav 	}
143*b7579f77SDag-Erling Smørgrav 	return 1;
144*b7579f77SDag-Erling Smørgrav }
145*b7579f77SDag-Erling Smørgrav 
146*b7579f77SDag-Erling Smørgrav /** massage input name */
147*b7579f77SDag-Erling Smørgrav static char*
148*b7579f77SDag-Erling Smørgrav massage_qname(const char* nm, int* reverse)
149*b7579f77SDag-Erling Smørgrav {
150*b7579f77SDag-Erling Smørgrav 	/* recognise IP4 and IP6, create reverse addresses if needed */
151*b7579f77SDag-Erling Smørgrav 	char* res;
152*b7579f77SDag-Erling Smørgrav 	if(isip4(nm, &res)) {
153*b7579f77SDag-Erling Smørgrav 		*reverse = 1;
154*b7579f77SDag-Erling Smørgrav 	} else if(isip6(nm, &res)) {
155*b7579f77SDag-Erling Smørgrav 		*reverse = 1;
156*b7579f77SDag-Erling Smørgrav 	} else {
157*b7579f77SDag-Erling Smørgrav 		res = strdup(nm);
158*b7579f77SDag-Erling Smørgrav 	}
159*b7579f77SDag-Erling Smørgrav 	if(!res) {
160*b7579f77SDag-Erling Smørgrav 		fprintf(stderr, "error: out of memory\n");
161*b7579f77SDag-Erling Smørgrav 		exit(1);
162*b7579f77SDag-Erling Smørgrav 	}
163*b7579f77SDag-Erling Smørgrav 	return res;
164*b7579f77SDag-Erling Smørgrav }
165*b7579f77SDag-Erling Smørgrav 
166*b7579f77SDag-Erling Smørgrav /** massage input type */
167*b7579f77SDag-Erling Smørgrav static int
168*b7579f77SDag-Erling Smørgrav massage_type(const char* t, int reverse, int* multi)
169*b7579f77SDag-Erling Smørgrav {
170*b7579f77SDag-Erling Smørgrav 	if(t) {
171*b7579f77SDag-Erling Smørgrav 		int r = ldns_get_rr_type_by_name(t);
172*b7579f77SDag-Erling Smørgrav 		if(r == 0 && strcasecmp(t, "TYPE0") != 0 &&
173*b7579f77SDag-Erling Smørgrav 			strcmp(t, "") != 0) {
174*b7579f77SDag-Erling Smørgrav 			fprintf(stderr, "error unknown type %s\n", t);
175*b7579f77SDag-Erling Smørgrav 			exit(1);
176*b7579f77SDag-Erling Smørgrav 		}
177*b7579f77SDag-Erling Smørgrav 		return r;
178*b7579f77SDag-Erling Smørgrav 	}
179*b7579f77SDag-Erling Smørgrav 	if(!t && reverse)
180*b7579f77SDag-Erling Smørgrav 		return LDNS_RR_TYPE_PTR;
181*b7579f77SDag-Erling Smørgrav 	*multi = 1;
182*b7579f77SDag-Erling Smørgrav 	return LDNS_RR_TYPE_A;
183*b7579f77SDag-Erling Smørgrav }
184*b7579f77SDag-Erling Smørgrav 
185*b7579f77SDag-Erling Smørgrav /** massage input class */
186*b7579f77SDag-Erling Smørgrav static int
187*b7579f77SDag-Erling Smørgrav massage_class(const char* c)
188*b7579f77SDag-Erling Smørgrav {
189*b7579f77SDag-Erling Smørgrav 	if(c) {
190*b7579f77SDag-Erling Smørgrav 		int r = ldns_get_rr_class_by_name(c);
191*b7579f77SDag-Erling Smørgrav 		if(r == 0 && strcasecmp(c, "CLASS0") != 0 &&
192*b7579f77SDag-Erling Smørgrav 			strcmp(c, "") != 0) {
193*b7579f77SDag-Erling Smørgrav 			fprintf(stderr, "error unknown class %s\n", c);
194*b7579f77SDag-Erling Smørgrav 			exit(1);
195*b7579f77SDag-Erling Smørgrav 		}
196*b7579f77SDag-Erling Smørgrav 		return r;
197*b7579f77SDag-Erling Smørgrav 	}
198*b7579f77SDag-Erling Smørgrav 	return LDNS_RR_CLASS_IN;
199*b7579f77SDag-Erling Smørgrav }
200*b7579f77SDag-Erling Smørgrav 
201*b7579f77SDag-Erling Smørgrav /** nice security status string */
202*b7579f77SDag-Erling Smørgrav static const char*
203*b7579f77SDag-Erling Smørgrav secure_str(struct ub_result* result)
204*b7579f77SDag-Erling Smørgrav {
205*b7579f77SDag-Erling Smørgrav 	if(result->secure) return "(secure)";
206*b7579f77SDag-Erling Smørgrav 	if(result->bogus) return "(BOGUS (security failure))";
207*b7579f77SDag-Erling Smørgrav 	return "(insecure)";
208*b7579f77SDag-Erling Smørgrav }
209*b7579f77SDag-Erling Smørgrav 
210*b7579f77SDag-Erling Smørgrav /** nice string for type */
211*b7579f77SDag-Erling Smørgrav static void
212*b7579f77SDag-Erling Smørgrav pretty_type(char* s, size_t len, int t)
213*b7579f77SDag-Erling Smørgrav {
214*b7579f77SDag-Erling Smørgrav 	char* d = ldns_rr_type2str(t);
215*b7579f77SDag-Erling Smørgrav 	snprintf(s, len, "%s", d);
216*b7579f77SDag-Erling Smørgrav 	free(d);
217*b7579f77SDag-Erling Smørgrav }
218*b7579f77SDag-Erling Smørgrav 
219*b7579f77SDag-Erling Smørgrav /** nice string for class */
220*b7579f77SDag-Erling Smørgrav static void
221*b7579f77SDag-Erling Smørgrav pretty_class(char* s, size_t len, int c)
222*b7579f77SDag-Erling Smørgrav {
223*b7579f77SDag-Erling Smørgrav 	char* d = ldns_rr_class2str(c);
224*b7579f77SDag-Erling Smørgrav 	snprintf(s, len, "%s", d);
225*b7579f77SDag-Erling Smørgrav 	free(d);
226*b7579f77SDag-Erling Smørgrav }
227*b7579f77SDag-Erling Smørgrav 
228*b7579f77SDag-Erling Smørgrav /** nice string for rcode */
229*b7579f77SDag-Erling Smørgrav static void
230*b7579f77SDag-Erling Smørgrav pretty_rcode(char* s, size_t len, int r)
231*b7579f77SDag-Erling Smørgrav {
232*b7579f77SDag-Erling Smørgrav 	ldns_lookup_table *rcode = ldns_lookup_by_id(ldns_rcodes, r);
233*b7579f77SDag-Erling Smørgrav 	if(rcode) {
234*b7579f77SDag-Erling Smørgrav 		snprintf(s, len, "%s", rcode->name);
235*b7579f77SDag-Erling Smørgrav 	} else {
236*b7579f77SDag-Erling Smørgrav 		snprintf(s, len, "RCODE%d", r);
237*b7579f77SDag-Erling Smørgrav 	}
238*b7579f77SDag-Erling Smørgrav }
239*b7579f77SDag-Erling Smørgrav 
240*b7579f77SDag-Erling Smørgrav /** convert and print rdata */
241*b7579f77SDag-Erling Smørgrav static void
242*b7579f77SDag-Erling Smørgrav print_rd(int t, char* data, size_t len)
243*b7579f77SDag-Erling Smørgrav {
244*b7579f77SDag-Erling Smørgrav 	size_t i, pos = 0;
245*b7579f77SDag-Erling Smørgrav 	uint8_t* rd = (uint8_t*)malloc(len+2);
246*b7579f77SDag-Erling Smørgrav 	ldns_rr* rr = ldns_rr_new();
247*b7579f77SDag-Erling Smørgrav 	ldns_status status;
248*b7579f77SDag-Erling Smørgrav 	if(!rd || !rr) {
249*b7579f77SDag-Erling Smørgrav 		fprintf(stderr, "out of memory");
250*b7579f77SDag-Erling Smørgrav 		exit(1);
251*b7579f77SDag-Erling Smørgrav 	}
252*b7579f77SDag-Erling Smørgrav 	ldns_rr_set_type(rr, t);
253*b7579f77SDag-Erling Smørgrav 	ldns_write_uint16(rd, len);
254*b7579f77SDag-Erling Smørgrav 	memmove(rd+2, data, len);
255*b7579f77SDag-Erling Smørgrav 	ldns_rr_set_owner(rr, NULL);
256*b7579f77SDag-Erling Smørgrav 	status = ldns_wire2rdf(rr, rd, len+2, &pos);
257*b7579f77SDag-Erling Smørgrav 	if(status != LDNS_STATUS_OK) {
258*b7579f77SDag-Erling Smørgrav 		free(rd);
259*b7579f77SDag-Erling Smørgrav 		ldns_rr_free(rr);
260*b7579f77SDag-Erling Smørgrav 		printf("error_printing_data");
261*b7579f77SDag-Erling Smørgrav 		return;
262*b7579f77SDag-Erling Smørgrav 	}
263*b7579f77SDag-Erling Smørgrav 	for(i=0; i<ldns_rr_rd_count(rr); i++) {
264*b7579f77SDag-Erling Smørgrav 		printf(" ");
265*b7579f77SDag-Erling Smørgrav 		ldns_rdf_print(stdout, ldns_rr_rdf(rr, i));
266*b7579f77SDag-Erling Smørgrav 	}
267*b7579f77SDag-Erling Smørgrav 	ldns_rr_free(rr);
268*b7579f77SDag-Erling Smørgrav 	free(rd);
269*b7579f77SDag-Erling Smørgrav }
270*b7579f77SDag-Erling Smørgrav 
271*b7579f77SDag-Erling Smørgrav /** pretty line of RR data for results */
272*b7579f77SDag-Erling Smørgrav static void
273*b7579f77SDag-Erling Smørgrav pretty_rdata(char* q, char* cstr, char* tstr, int t, const char* sec,
274*b7579f77SDag-Erling Smørgrav 	char* data, size_t len)
275*b7579f77SDag-Erling Smørgrav {
276*b7579f77SDag-Erling Smørgrav 	printf("%s", q);
277*b7579f77SDag-Erling Smørgrav 	if(strcmp(cstr, "IN") != 0)
278*b7579f77SDag-Erling Smørgrav 		printf(" in class %s", cstr);
279*b7579f77SDag-Erling Smørgrav 	if(t == LDNS_RR_TYPE_A)
280*b7579f77SDag-Erling Smørgrav 		printf(" has address");
281*b7579f77SDag-Erling Smørgrav 	else if(t == LDNS_RR_TYPE_AAAA)
282*b7579f77SDag-Erling Smørgrav 		printf(" has IPv6 address");
283*b7579f77SDag-Erling Smørgrav 	else if(t == LDNS_RR_TYPE_MX)
284*b7579f77SDag-Erling Smørgrav 		printf(" mail is handled by");
285*b7579f77SDag-Erling Smørgrav 	else if(t == LDNS_RR_TYPE_PTR)
286*b7579f77SDag-Erling Smørgrav 		printf(" domain name pointer");
287*b7579f77SDag-Erling Smørgrav 	else	printf(" has %s record", tstr);
288*b7579f77SDag-Erling Smørgrav 	print_rd(t, data, len);
289*b7579f77SDag-Erling Smørgrav 	if(verb > 0)
290*b7579f77SDag-Erling Smørgrav 		printf(" %s", sec);
291*b7579f77SDag-Erling Smørgrav 	printf("\n");
292*b7579f77SDag-Erling Smørgrav }
293*b7579f77SDag-Erling Smørgrav 
294*b7579f77SDag-Erling Smørgrav /** pretty line of output for results */
295*b7579f77SDag-Erling Smørgrav static void
296*b7579f77SDag-Erling Smørgrav pretty_output(char* q, int t, int c, struct ub_result* result, int docname)
297*b7579f77SDag-Erling Smørgrav {
298*b7579f77SDag-Erling Smørgrav 	int i;
299*b7579f77SDag-Erling Smørgrav 	const char *secstatus = secure_str(result);
300*b7579f77SDag-Erling Smørgrav 	char tstr[16];
301*b7579f77SDag-Erling Smørgrav 	char cstr[16];
302*b7579f77SDag-Erling Smørgrav 	char rcodestr[16];
303*b7579f77SDag-Erling Smørgrav 	pretty_type(tstr, 16, t);
304*b7579f77SDag-Erling Smørgrav 	pretty_class(cstr, 16, c);
305*b7579f77SDag-Erling Smørgrav 	pretty_rcode(rcodestr, 16, result->rcode);
306*b7579f77SDag-Erling Smørgrav 
307*b7579f77SDag-Erling Smørgrav 	if(!result->havedata && result->rcode) {
308*b7579f77SDag-Erling Smørgrav 		printf("Host %s not found: %d(%s).",
309*b7579f77SDag-Erling Smørgrav 			q, result->rcode, rcodestr);
310*b7579f77SDag-Erling Smørgrav 		if(verb > 0)
311*b7579f77SDag-Erling Smørgrav 			printf(" %s", secstatus);
312*b7579f77SDag-Erling Smørgrav 		printf("\n");
313*b7579f77SDag-Erling Smørgrav 		if(result->bogus && result->why_bogus)
314*b7579f77SDag-Erling Smørgrav 			printf("%s\n", result->why_bogus);
315*b7579f77SDag-Erling Smørgrav 		return;
316*b7579f77SDag-Erling Smørgrav 	}
317*b7579f77SDag-Erling Smørgrav 	if(docname && result->canonname &&
318*b7579f77SDag-Erling Smørgrav 		result->canonname != result->qname) {
319*b7579f77SDag-Erling Smørgrav 		printf("%s is an alias for %s", result->qname,
320*b7579f77SDag-Erling Smørgrav 			result->canonname);
321*b7579f77SDag-Erling Smørgrav 		if(verb > 0)
322*b7579f77SDag-Erling Smørgrav 			printf(" %s", secstatus);
323*b7579f77SDag-Erling Smørgrav 		printf("\n");
324*b7579f77SDag-Erling Smørgrav 	}
325*b7579f77SDag-Erling Smørgrav 	/* remove trailing . from long canonnames for nicer output */
326*b7579f77SDag-Erling Smørgrav 	if(result->canonname && strlen(result->canonname) > 1 &&
327*b7579f77SDag-Erling Smørgrav 		result->canonname[strlen(result->canonname)-1] == '.')
328*b7579f77SDag-Erling Smørgrav 		result->canonname[strlen(result->canonname)-1] = 0;
329*b7579f77SDag-Erling Smørgrav 	if(!result->havedata) {
330*b7579f77SDag-Erling Smørgrav 		if(verb > 0) {
331*b7579f77SDag-Erling Smørgrav 			printf("%s", result->canonname?result->canonname:q);
332*b7579f77SDag-Erling Smørgrav 			if(strcmp(cstr, "IN") != 0)
333*b7579f77SDag-Erling Smørgrav 				printf(" in class %s", cstr);
334*b7579f77SDag-Erling Smørgrav 			if(t == LDNS_RR_TYPE_A)
335*b7579f77SDag-Erling Smørgrav 				printf(" has no address");
336*b7579f77SDag-Erling Smørgrav 			else if(t == LDNS_RR_TYPE_AAAA)
337*b7579f77SDag-Erling Smørgrav 				printf(" has no IPv6 address");
338*b7579f77SDag-Erling Smørgrav 			else if(t == LDNS_RR_TYPE_PTR)
339*b7579f77SDag-Erling Smørgrav 				printf(" has no domain name ptr");
340*b7579f77SDag-Erling Smørgrav 			else if(t == LDNS_RR_TYPE_MX)
341*b7579f77SDag-Erling Smørgrav 				printf(" has no mail handler record");
342*b7579f77SDag-Erling Smørgrav 			else if(t == LDNS_RR_TYPE_ANY) {
343*b7579f77SDag-Erling Smørgrav 				ldns_pkt* p = NULL;
344*b7579f77SDag-Erling Smørgrav 				if(ldns_wire2pkt(&p, result->answer_packet,
345*b7579f77SDag-Erling Smørgrav 				  (size_t)result->answer_len)==LDNS_STATUS_OK){
346*b7579f77SDag-Erling Smørgrav 					if(ldns_rr_list_rr_count(
347*b7579f77SDag-Erling Smørgrav 						ldns_pkt_answer(p)) == 0)
348*b7579f77SDag-Erling Smørgrav 						printf(" has no records\n");
349*b7579f77SDag-Erling Smørgrav 					else {
350*b7579f77SDag-Erling Smørgrav 						printf(" ANY:\n");
351*b7579f77SDag-Erling Smørgrav 						ldns_rr_list_print(stdout,
352*b7579f77SDag-Erling Smørgrav 							ldns_pkt_answer(p));
353*b7579f77SDag-Erling Smørgrav 					}
354*b7579f77SDag-Erling Smørgrav 				} else {
355*b7579f77SDag-Erling Smørgrav 					fprintf(stderr, "could not parse "
356*b7579f77SDag-Erling Smørgrav 						"reply packet to ANY query\n");
357*b7579f77SDag-Erling Smørgrav 					exit(1);
358*b7579f77SDag-Erling Smørgrav 				}
359*b7579f77SDag-Erling Smørgrav 				ldns_pkt_free(p);
360*b7579f77SDag-Erling Smørgrav 
361*b7579f77SDag-Erling Smørgrav 			} else	printf(" has no %s record", tstr);
362*b7579f77SDag-Erling Smørgrav 			printf(" %s\n", secstatus);
363*b7579f77SDag-Erling Smørgrav 		}
364*b7579f77SDag-Erling Smørgrav 		/* else: emptiness to indicate no data */
365*b7579f77SDag-Erling Smørgrav 		if(result->bogus && result->why_bogus)
366*b7579f77SDag-Erling Smørgrav 			printf("%s\n", result->why_bogus);
367*b7579f77SDag-Erling Smørgrav 		return;
368*b7579f77SDag-Erling Smørgrav 	}
369*b7579f77SDag-Erling Smørgrav 	i=0;
370*b7579f77SDag-Erling Smørgrav 	while(result->data[i])
371*b7579f77SDag-Erling Smørgrav 	{
372*b7579f77SDag-Erling Smørgrav 		pretty_rdata(
373*b7579f77SDag-Erling Smørgrav 			result->canonname?result->canonname:q,
374*b7579f77SDag-Erling Smørgrav 			cstr, tstr, t, secstatus, result->data[i],
375*b7579f77SDag-Erling Smørgrav 			(size_t)result->len[i]);
376*b7579f77SDag-Erling Smørgrav 		i++;
377*b7579f77SDag-Erling Smørgrav 	}
378*b7579f77SDag-Erling Smørgrav 	if(result->bogus && result->why_bogus)
379*b7579f77SDag-Erling Smørgrav 		printf("%s\n", result->why_bogus);
380*b7579f77SDag-Erling Smørgrav }
381*b7579f77SDag-Erling Smørgrav 
382*b7579f77SDag-Erling Smørgrav /** perform a lookup and printout return if domain existed */
383*b7579f77SDag-Erling Smørgrav static int
384*b7579f77SDag-Erling Smørgrav dnslook(struct ub_ctx* ctx, char* q, int t, int c, int docname)
385*b7579f77SDag-Erling Smørgrav {
386*b7579f77SDag-Erling Smørgrav 	int ret;
387*b7579f77SDag-Erling Smørgrav 	struct ub_result* result;
388*b7579f77SDag-Erling Smørgrav 
389*b7579f77SDag-Erling Smørgrav 	ret = ub_resolve(ctx, q, t, c, &result);
390*b7579f77SDag-Erling Smørgrav 	if(ret != 0) {
391*b7579f77SDag-Erling Smørgrav 		fprintf(stderr, "resolve error: %s\n", ub_strerror(ret));
392*b7579f77SDag-Erling Smørgrav 		exit(1);
393*b7579f77SDag-Erling Smørgrav 	}
394*b7579f77SDag-Erling Smørgrav 	pretty_output(q, t, c, result, docname);
395*b7579f77SDag-Erling Smørgrav 	ret = result->nxdomain;
396*b7579f77SDag-Erling Smørgrav 	ub_resolve_free(result);
397*b7579f77SDag-Erling Smørgrav 	return ret;
398*b7579f77SDag-Erling Smørgrav }
399*b7579f77SDag-Erling Smørgrav 
400*b7579f77SDag-Erling Smørgrav /** perform host lookup */
401*b7579f77SDag-Erling Smørgrav static void
402*b7579f77SDag-Erling Smørgrav lookup(struct ub_ctx* ctx, const char* nm, const char* qt, const char* qc)
403*b7579f77SDag-Erling Smørgrav {
404*b7579f77SDag-Erling Smørgrav 	/* massage input into a query name, type and class */
405*b7579f77SDag-Erling Smørgrav 	int multi = 0;	 /* no type, so do A, AAAA, MX */
406*b7579f77SDag-Erling Smørgrav 	int reverse = 0; /* we are doing a reverse lookup */
407*b7579f77SDag-Erling Smørgrav 	char* realq = massage_qname(nm, &reverse);
408*b7579f77SDag-Erling Smørgrav 	int t = massage_type(qt, reverse, &multi);
409*b7579f77SDag-Erling Smørgrav 	int c = massage_class(qc);
410*b7579f77SDag-Erling Smørgrav 
411*b7579f77SDag-Erling Smørgrav 	/* perform the query */
412*b7579f77SDag-Erling Smørgrav 	if(multi) {
413*b7579f77SDag-Erling Smørgrav 		if(!dnslook(ctx, realq, LDNS_RR_TYPE_A, c, 1)) {
414*b7579f77SDag-Erling Smørgrav 			/* domain exists, lookup more */
415*b7579f77SDag-Erling Smørgrav 			(void)dnslook(ctx, realq, LDNS_RR_TYPE_AAAA, c, 0);
416*b7579f77SDag-Erling Smørgrav 			(void)dnslook(ctx, realq, LDNS_RR_TYPE_MX, c, 0);
417*b7579f77SDag-Erling Smørgrav 		}
418*b7579f77SDag-Erling Smørgrav 	} else {
419*b7579f77SDag-Erling Smørgrav 		(void)dnslook(ctx, realq, t, c, 1);
420*b7579f77SDag-Erling Smørgrav 	}
421*b7579f77SDag-Erling Smørgrav 	ub_ctx_delete(ctx);
422*b7579f77SDag-Erling Smørgrav 	free(realq);
423*b7579f77SDag-Erling Smørgrav }
424*b7579f77SDag-Erling Smørgrav 
425*b7579f77SDag-Erling Smørgrav /** print error if any */
426*b7579f77SDag-Erling Smørgrav static void
427*b7579f77SDag-Erling Smørgrav check_ub_res(int r)
428*b7579f77SDag-Erling Smørgrav {
429*b7579f77SDag-Erling Smørgrav 	if(r != 0) {
430*b7579f77SDag-Erling Smørgrav 		fprintf(stderr, "error: %s\n", ub_strerror(r));
431*b7579f77SDag-Erling Smørgrav 		exit(1);
432*b7579f77SDag-Erling Smørgrav 	}
433*b7579f77SDag-Erling Smørgrav }
434*b7579f77SDag-Erling Smørgrav 
435*b7579f77SDag-Erling Smørgrav /** getopt global, in case header files fail to declare it. */
436*b7579f77SDag-Erling Smørgrav extern int optind;
437*b7579f77SDag-Erling Smørgrav /** getopt global, in case header files fail to declare it. */
438*b7579f77SDag-Erling Smørgrav extern char* optarg;
439*b7579f77SDag-Erling Smørgrav 
440*b7579f77SDag-Erling Smørgrav /** Main routine for checkconf */
441*b7579f77SDag-Erling Smørgrav int main(int argc, char* argv[])
442*b7579f77SDag-Erling Smørgrav {
443*b7579f77SDag-Erling Smørgrav 	int c;
444*b7579f77SDag-Erling Smørgrav 	char* qclass = NULL;
445*b7579f77SDag-Erling Smørgrav 	char* qtype = NULL;
446*b7579f77SDag-Erling Smørgrav 	struct ub_ctx* ctx = NULL;
447*b7579f77SDag-Erling Smørgrav 	int debuglevel = 0;
448*b7579f77SDag-Erling Smørgrav 
449*b7579f77SDag-Erling Smørgrav 	ctx = ub_ctx_create();
450*b7579f77SDag-Erling Smørgrav 	if(!ctx) {
451*b7579f77SDag-Erling Smørgrav 		fprintf(stderr, "error: out of memory\n");
452*b7579f77SDag-Erling Smørgrav 		exit(1);
453*b7579f77SDag-Erling Smørgrav 	}
454*b7579f77SDag-Erling Smørgrav 
455*b7579f77SDag-Erling Smørgrav 	/* parse the options */
456*b7579f77SDag-Erling Smørgrav 	while( (c=getopt(argc, argv, "46F:c:df:hrt:vy:C:")) != -1) {
457*b7579f77SDag-Erling Smørgrav 		switch(c) {
458*b7579f77SDag-Erling Smørgrav 		case '4':
459*b7579f77SDag-Erling Smørgrav 			check_ub_res(ub_ctx_set_option(ctx, "do-ip6:", "no"));
460*b7579f77SDag-Erling Smørgrav 			break;
461*b7579f77SDag-Erling Smørgrav 		case '6':
462*b7579f77SDag-Erling Smørgrav 			check_ub_res(ub_ctx_set_option(ctx, "do-ip4:", "no"));
463*b7579f77SDag-Erling Smørgrav 			break;
464*b7579f77SDag-Erling Smørgrav 		case 'c':
465*b7579f77SDag-Erling Smørgrav 			qclass = optarg;
466*b7579f77SDag-Erling Smørgrav 			break;
467*b7579f77SDag-Erling Smørgrav 		case 'C':
468*b7579f77SDag-Erling Smørgrav 			check_ub_res(ub_ctx_config(ctx, optarg));
469*b7579f77SDag-Erling Smørgrav 			break;
470*b7579f77SDag-Erling Smørgrav 		case 'd':
471*b7579f77SDag-Erling Smørgrav 			debuglevel++;
472*b7579f77SDag-Erling Smørgrav 			if(debuglevel < 2)
473*b7579f77SDag-Erling Smørgrav 				debuglevel = 2; /* at least VERB_DETAIL */
474*b7579f77SDag-Erling Smørgrav 			break;
475*b7579f77SDag-Erling Smørgrav 		case 'r':
476*b7579f77SDag-Erling Smørgrav 			check_ub_res(ub_ctx_resolvconf(ctx, "/etc/resolv.conf"));
477*b7579f77SDag-Erling Smørgrav 			break;
478*b7579f77SDag-Erling Smørgrav 		case 't':
479*b7579f77SDag-Erling Smørgrav 			qtype = optarg;
480*b7579f77SDag-Erling Smørgrav 			break;
481*b7579f77SDag-Erling Smørgrav 		case 'v':
482*b7579f77SDag-Erling Smørgrav 			verb++;
483*b7579f77SDag-Erling Smørgrav 			break;
484*b7579f77SDag-Erling Smørgrav 		case 'y':
485*b7579f77SDag-Erling Smørgrav 			check_ub_res(ub_ctx_add_ta(ctx, optarg));
486*b7579f77SDag-Erling Smørgrav 			break;
487*b7579f77SDag-Erling Smørgrav 		case 'f':
488*b7579f77SDag-Erling Smørgrav 			check_ub_res(ub_ctx_add_ta_file(ctx, optarg));
489*b7579f77SDag-Erling Smørgrav 			break;
490*b7579f77SDag-Erling Smørgrav 		case 'F':
491*b7579f77SDag-Erling Smørgrav 			check_ub_res(ub_ctx_trustedkeys(ctx, optarg));
492*b7579f77SDag-Erling Smørgrav 			break;
493*b7579f77SDag-Erling Smørgrav 		case '?':
494*b7579f77SDag-Erling Smørgrav 		case 'h':
495*b7579f77SDag-Erling Smørgrav 		default:
496*b7579f77SDag-Erling Smørgrav 			usage();
497*b7579f77SDag-Erling Smørgrav 		}
498*b7579f77SDag-Erling Smørgrav 	}
499*b7579f77SDag-Erling Smørgrav 	if(debuglevel != 0) /* set after possible -C options */
500*b7579f77SDag-Erling Smørgrav 		check_ub_res(ub_ctx_debuglevel(ctx, debuglevel));
501*b7579f77SDag-Erling Smørgrav 	if(ub_ctx_get_option(ctx, "use-syslog", &optarg) == 0) {
502*b7579f77SDag-Erling Smørgrav 		if(strcmp(optarg, "yes") == 0) /* disable use-syslog */
503*b7579f77SDag-Erling Smørgrav 			check_ub_res(ub_ctx_set_option(ctx,
504*b7579f77SDag-Erling Smørgrav 				"use-syslog:", "no"));
505*b7579f77SDag-Erling Smørgrav 		free(optarg);
506*b7579f77SDag-Erling Smørgrav 	}
507*b7579f77SDag-Erling Smørgrav 	argc -= optind;
508*b7579f77SDag-Erling Smørgrav 	argv += optind;
509*b7579f77SDag-Erling Smørgrav 	if(argc != 1)
510*b7579f77SDag-Erling Smørgrav 		usage();
511*b7579f77SDag-Erling Smørgrav 
512*b7579f77SDag-Erling Smørgrav 	lookup(ctx, argv[0], qtype, qclass);
513*b7579f77SDag-Erling Smørgrav 	return 0;
514*b7579f77SDag-Erling Smørgrav }
515