xref: /freebsd/contrib/ldns-host/ldns-host.c (revision 3fc9e2c36555140de248a0b4def91bbfa44d7c2c)
1*3fc9e2c3SDag-Erling Smørgrav /*-
2*3fc9e2c3SDag-Erling Smørgrav  * (c) Magerya Vitaly
3*3fc9e2c3SDag-Erling Smørgrav  *
4*3fc9e2c3SDag-Erling Smørgrav  * Copying and distribution of this file, with or without modification,
5*3fc9e2c3SDag-Erling Smørgrav  * are permitted in any medium without royalty provided the copyright
6*3fc9e2c3SDag-Erling Smørgrav  * notice and this notice are preserved. This file is offered as-is,
7*3fc9e2c3SDag-Erling Smørgrav  * without any warranty.
8*3fc9e2c3SDag-Erling Smørgrav  */
9*3fc9e2c3SDag-Erling Smørgrav 
10*3fc9e2c3SDag-Erling Smørgrav #include <netinet/in.h>
11*3fc9e2c3SDag-Erling Smørgrav 
12*3fc9e2c3SDag-Erling Smørgrav #include <limits.h>
13*3fc9e2c3SDag-Erling Smørgrav #include <netdb.h>
14*3fc9e2c3SDag-Erling Smørgrav #include <stdio.h>
15*3fc9e2c3SDag-Erling Smørgrav #include <stdlib.h>
16*3fc9e2c3SDag-Erling Smørgrav #include <unistd.h>
17*3fc9e2c3SDag-Erling Smørgrav 
18*3fc9e2c3SDag-Erling Smørgrav #include <ldns/ldns.h>
19*3fc9e2c3SDag-Erling Smørgrav 
20*3fc9e2c3SDag-Erling Smørgrav /* General utilities.
21*3fc9e2c3SDag-Erling Smørgrav  */
22*3fc9e2c3SDag-Erling Smørgrav 
23*3fc9e2c3SDag-Erling Smørgrav static char *progname;
24*3fc9e2c3SDag-Erling Smørgrav 
25*3fc9e2c3SDag-Erling Smørgrav #define countof(array) (sizeof(array)/sizeof(*(array)))
26*3fc9e2c3SDag-Erling Smørgrav 
27*3fc9e2c3SDag-Erling Smørgrav static void
28*3fc9e2c3SDag-Erling Smørgrav die(int code, const char *fmt, ...) {
29*3fc9e2c3SDag-Erling Smørgrav     va_list args;
30*3fc9e2c3SDag-Erling Smørgrav 
31*3fc9e2c3SDag-Erling Smørgrav     va_start(args, fmt);
32*3fc9e2c3SDag-Erling Smørgrav     fprintf(stderr, "%s: ", progname);
33*3fc9e2c3SDag-Erling Smørgrav     vfprintf(stderr, fmt, args);
34*3fc9e2c3SDag-Erling Smørgrav     fprintf(stderr, "\n");
35*3fc9e2c3SDag-Erling Smørgrav     va_end(args);
36*3fc9e2c3SDag-Erling Smørgrav     exit(code);
37*3fc9e2c3SDag-Erling Smørgrav }
38*3fc9e2c3SDag-Erling Smørgrav 
39*3fc9e2c3SDag-Erling Smørgrav static int
40*3fc9e2c3SDag-Erling Smørgrav ndots(const char *name) {
41*3fc9e2c3SDag-Erling Smørgrav     int n;
42*3fc9e2c3SDag-Erling Smørgrav 
43*3fc9e2c3SDag-Erling Smørgrav     for (n = 0; (name = strchr(name, '.')); n++, name++);
44*3fc9e2c3SDag-Erling Smørgrav     return n;
45*3fc9e2c3SDag-Erling Smørgrav }
46*3fc9e2c3SDag-Erling Smørgrav 
47*3fc9e2c3SDag-Erling Smørgrav /* General LDNS-specific utilities.
48*3fc9e2c3SDag-Erling Smørgrav  */
49*3fc9e2c3SDag-Erling Smørgrav 
50*3fc9e2c3SDag-Erling Smørgrav static ldns_status
51*3fc9e2c3SDag-Erling Smørgrav ldns_resolver_new_default(ldns_resolver **res) {
52*3fc9e2c3SDag-Erling Smørgrav     if (ldns_resolver_new_frm_file(res, NULL) == LDNS_STATUS_OK ||
53*3fc9e2c3SDag-Erling Smørgrav         (*res = ldns_resolver_new()) != NULL)
54*3fc9e2c3SDag-Erling Smørgrav         return LDNS_STATUS_OK;
55*3fc9e2c3SDag-Erling Smørgrav     return LDNS_STATUS_MEM_ERR;
56*3fc9e2c3SDag-Erling Smørgrav }
57*3fc9e2c3SDag-Erling Smørgrav 
58*3fc9e2c3SDag-Erling Smørgrav static ldns_status
59*3fc9e2c3SDag-Erling Smørgrav ldns_resolver_push_default_servers(ldns_resolver *res) {
60*3fc9e2c3SDag-Erling Smørgrav     ldns_status status;
61*3fc9e2c3SDag-Erling Smørgrav     ldns_rdf *addr;
62*3fc9e2c3SDag-Erling Smørgrav 
63*3fc9e2c3SDag-Erling Smørgrav     if ((status = ldns_str2rdf_a(&addr, "127.0.0.1")) != LDNS_STATUS_OK ||
64*3fc9e2c3SDag-Erling Smørgrav         (status = ldns_resolver_push_nameserver(res, addr)) != LDNS_STATUS_OK)
65*3fc9e2c3SDag-Erling Smørgrav         return ldns_rdf_deep_free(addr), status;
66*3fc9e2c3SDag-Erling Smørgrav     ldns_rdf_deep_free(addr);
67*3fc9e2c3SDag-Erling Smørgrav     if ((status = ldns_str2rdf_aaaa(&addr, "::1")) != LDNS_STATUS_OK ||
68*3fc9e2c3SDag-Erling Smørgrav         (status = ldns_resolver_push_nameserver(res, addr)) != LDNS_STATUS_OK)
69*3fc9e2c3SDag-Erling Smørgrav         return ldns_rdf_deep_free(addr), status;
70*3fc9e2c3SDag-Erling Smørgrav     ldns_rdf_deep_free(addr);
71*3fc9e2c3SDag-Erling Smørgrav     return LDNS_STATUS_OK;
72*3fc9e2c3SDag-Erling Smørgrav }
73*3fc9e2c3SDag-Erling Smørgrav 
74*3fc9e2c3SDag-Erling Smørgrav static ldns_rdf *
75*3fc9e2c3SDag-Erling Smørgrav ldns_rdf_new_addr_frm_str(const char *str) {
76*3fc9e2c3SDag-Erling Smørgrav     ldns_rdf *addr;
77*3fc9e2c3SDag-Erling Smørgrav 
78*3fc9e2c3SDag-Erling Smørgrav     if ((addr = ldns_rdf_new_frm_str(LDNS_RDF_TYPE_A, str)) == NULL)
79*3fc9e2c3SDag-Erling Smørgrav         addr = ldns_rdf_new_frm_str(LDNS_RDF_TYPE_AAAA, str);
80*3fc9e2c3SDag-Erling Smørgrav     return addr;
81*3fc9e2c3SDag-Erling Smørgrav }
82*3fc9e2c3SDag-Erling Smørgrav 
83*3fc9e2c3SDag-Erling Smørgrav static void
84*3fc9e2c3SDag-Erling Smørgrav ldns_resolver_remove_nameservers(ldns_resolver *res) {
85*3fc9e2c3SDag-Erling Smørgrav     while (ldns_resolver_nameserver_count(res) > 0)
86*3fc9e2c3SDag-Erling Smørgrav         ldns_rdf_deep_free(ldns_resolver_pop_nameserver(res));
87*3fc9e2c3SDag-Erling Smørgrav }
88*3fc9e2c3SDag-Erling Smørgrav 
89*3fc9e2c3SDag-Erling Smørgrav static ldns_rdf *
90*3fc9e2c3SDag-Erling Smørgrav ldns_rdf_reverse_a(ldns_rdf *addr, const char *base) {
91*3fc9e2c3SDag-Erling Smørgrav     char *buf;
92*3fc9e2c3SDag-Erling Smørgrav     int i, len;
93*3fc9e2c3SDag-Erling Smørgrav 
94*3fc9e2c3SDag-Erling Smørgrav     len = strlen(base);
95*3fc9e2c3SDag-Erling Smørgrav     buf = alloca(LDNS_IP4ADDRLEN*4 + len + 1);
96*3fc9e2c3SDag-Erling Smørgrav     for (len = i = 0; i < LDNS_IP4ADDRLEN; i++)
97*3fc9e2c3SDag-Erling Smørgrav         len += sprintf(&buf[len], "%d.",
98*3fc9e2c3SDag-Erling Smørgrav             (int)ldns_rdf_data(addr)[LDNS_IP4ADDRLEN - i - 1]);
99*3fc9e2c3SDag-Erling Smørgrav     sprintf(&buf[len], "%s", base);
100*3fc9e2c3SDag-Erling Smørgrav     return ldns_dname_new_frm_str(buf);
101*3fc9e2c3SDag-Erling Smørgrav }
102*3fc9e2c3SDag-Erling Smørgrav 
103*3fc9e2c3SDag-Erling Smørgrav static ldns_rdf *
104*3fc9e2c3SDag-Erling Smørgrav ldns_rdf_reverse_aaaa(ldns_rdf *addr, const char *base) {
105*3fc9e2c3SDag-Erling Smørgrav     char *buf;
106*3fc9e2c3SDag-Erling Smørgrav     int i, len;
107*3fc9e2c3SDag-Erling Smørgrav 
108*3fc9e2c3SDag-Erling Smørgrav     len = strlen(base);
109*3fc9e2c3SDag-Erling Smørgrav     buf = alloca(LDNS_IP6ADDRLEN*4 + len + 1);
110*3fc9e2c3SDag-Erling Smørgrav     for (i = 0; i < LDNS_IP6ADDRLEN; i++) {
111*3fc9e2c3SDag-Erling Smørgrav         uint8_t byte = ldns_rdf_data(addr)[LDNS_IP6ADDRLEN - i - 1];
112*3fc9e2c3SDag-Erling Smørgrav         sprintf(&buf[i*4], "%x.%x.", byte & 0x0F, byte >> 4);
113*3fc9e2c3SDag-Erling Smørgrav     }
114*3fc9e2c3SDag-Erling Smørgrav     sprintf(&buf[LDNS_IP6ADDRLEN*4], "%s", base);
115*3fc9e2c3SDag-Erling Smørgrav     return ldns_dname_new_frm_str(buf);
116*3fc9e2c3SDag-Erling Smørgrav }
117*3fc9e2c3SDag-Erling Smørgrav 
118*3fc9e2c3SDag-Erling Smørgrav static ldns_status
119*3fc9e2c3SDag-Erling Smørgrav ldns_pkt_push_rr_soa(ldns_pkt *pkt, ldns_pkt_section sec,
120*3fc9e2c3SDag-Erling Smørgrav     const ldns_rdf *name, ldns_rr_class c, uint32_t serial) {
121*3fc9e2c3SDag-Erling Smørgrav     ldns_rdf *rdf;
122*3fc9e2c3SDag-Erling Smørgrav     ldns_rr *rr;
123*3fc9e2c3SDag-Erling Smørgrav     uint32_t n;
124*3fc9e2c3SDag-Erling Smørgrav 
125*3fc9e2c3SDag-Erling Smørgrav     if ((rr = ldns_rr_new_frm_type(LDNS_RR_TYPE_SOA)) == NULL)
126*3fc9e2c3SDag-Erling Smørgrav         return LDNS_STATUS_MEM_ERR;
127*3fc9e2c3SDag-Erling Smørgrav     ldns_rr_set_class(rr, c);
128*3fc9e2c3SDag-Erling Smørgrav     ldns_rr_set_owner(rr, ldns_rdf_clone(name));
129*3fc9e2c3SDag-Erling Smørgrav     ldns_rr_set_ttl(rr, 0);
130*3fc9e2c3SDag-Erling Smørgrav 
131*3fc9e2c3SDag-Erling Smørgrav     n = 0;
132*3fc9e2c3SDag-Erling Smørgrav     if ((rdf = ldns_rdf_new_frm_data(LDNS_RDF_TYPE_DNAME, 1, &n)) == NULL)
133*3fc9e2c3SDag-Erling Smørgrav         goto memerr;
134*3fc9e2c3SDag-Erling Smørgrav     ldns_rr_set_rdf(rr, rdf, 0);
135*3fc9e2c3SDag-Erling Smørgrav     ldns_rr_set_rdf(rr, ldns_rdf_clone(rdf), 1);
136*3fc9e2c3SDag-Erling Smørgrav 
137*3fc9e2c3SDag-Erling Smørgrav     n = htonl(serial);
138*3fc9e2c3SDag-Erling Smørgrav     if ((rdf = ldns_rdf_new_frm_data(LDNS_RDF_TYPE_INT32, 4, &n)) == NULL)
139*3fc9e2c3SDag-Erling Smørgrav         goto memerr;
140*3fc9e2c3SDag-Erling Smørgrav     ldns_rr_set_rdf(rr, rdf, 2);
141*3fc9e2c3SDag-Erling Smørgrav 
142*3fc9e2c3SDag-Erling Smørgrav     n = 0;
143*3fc9e2c3SDag-Erling Smørgrav     if ((rdf = ldns_rdf_new_frm_data(LDNS_RDF_TYPE_PERIOD, 4, &n)) == NULL)
144*3fc9e2c3SDag-Erling Smørgrav         goto memerr;
145*3fc9e2c3SDag-Erling Smørgrav     ldns_rr_set_rdf(rr, rdf, 3);
146*3fc9e2c3SDag-Erling Smørgrav     ldns_rr_set_rdf(rr, ldns_rdf_clone(rdf), 4);
147*3fc9e2c3SDag-Erling Smørgrav     ldns_rr_set_rdf(rr, ldns_rdf_clone(rdf), 5);
148*3fc9e2c3SDag-Erling Smørgrav     ldns_rr_set_rdf(rr, ldns_rdf_clone(rdf), 6);
149*3fc9e2c3SDag-Erling Smørgrav 
150*3fc9e2c3SDag-Erling Smørgrav     if (ldns_rr_rdf(rr, 1) == NULL || ldns_rr_rdf(rr, 4) == NULL ||
151*3fc9e2c3SDag-Erling Smørgrav         ldns_rr_rdf(rr, 5) == NULL || ldns_rr_rdf(rr, 6) == NULL ||
152*3fc9e2c3SDag-Erling Smørgrav         !ldns_pkt_push_rr(pkt, sec, rr))
153*3fc9e2c3SDag-Erling Smørgrav         goto memerr;
154*3fc9e2c3SDag-Erling Smørgrav     return LDNS_STATUS_OK;
155*3fc9e2c3SDag-Erling Smørgrav 
156*3fc9e2c3SDag-Erling Smørgrav memerr:
157*3fc9e2c3SDag-Erling Smørgrav     ldns_rr_free(rr);
158*3fc9e2c3SDag-Erling Smørgrav     return LDNS_STATUS_MEM_ERR;
159*3fc9e2c3SDag-Erling Smørgrav }
160*3fc9e2c3SDag-Erling Smørgrav 
161*3fc9e2c3SDag-Erling Smørgrav static ldns_status
162*3fc9e2c3SDag-Erling Smørgrav ldns_resolver_send_to(ldns_pkt **answer, ldns_resolver *res,
163*3fc9e2c3SDag-Erling Smørgrav     const ldns_rdf *name, ldns_rr_type t, ldns_rr_class c,
164*3fc9e2c3SDag-Erling Smørgrav     uint16_t flags, uint32_t ixfr_serial, int nameserver) {
165*3fc9e2c3SDag-Erling Smørgrav     ldns_status status;
166*3fc9e2c3SDag-Erling Smørgrav     ldns_pkt *qpkt;
167*3fc9e2c3SDag-Erling Smørgrav 
168*3fc9e2c3SDag-Erling Smørgrav     int nscnt = ldns_resolver_nameserver_count(res);
169*3fc9e2c3SDag-Erling Smørgrav     ldns_rdf **ns = ldns_resolver_nameservers(res);
170*3fc9e2c3SDag-Erling Smørgrav     size_t *rtt = ldns_resolver_rtt(res);
171*3fc9e2c3SDag-Erling Smørgrav 
172*3fc9e2c3SDag-Erling Smørgrav     ldns_resolver_set_nameservers(res, &ns[nameserver]);
173*3fc9e2c3SDag-Erling Smørgrav     ldns_resolver_set_rtt(res, &rtt[nameserver]);
174*3fc9e2c3SDag-Erling Smørgrav     ldns_resolver_set_nameserver_count(res, 1);
175*3fc9e2c3SDag-Erling Smørgrav 
176*3fc9e2c3SDag-Erling Smørgrav     status = ldns_resolver_prepare_query_pkt(&qpkt, res, name, t, c, flags);
177*3fc9e2c3SDag-Erling Smørgrav     if (status == LDNS_STATUS_OK && t == LDNS_RR_TYPE_IXFR)
178*3fc9e2c3SDag-Erling Smørgrav         status = ldns_pkt_push_rr_soa(qpkt,
179*3fc9e2c3SDag-Erling Smørgrav             LDNS_SECTION_AUTHORITY, name, c, ixfr_serial);
180*3fc9e2c3SDag-Erling Smørgrav     if (status == LDNS_STATUS_OK)
181*3fc9e2c3SDag-Erling Smørgrav         status = ldns_resolver_send_pkt(answer, res, qpkt);
182*3fc9e2c3SDag-Erling Smørgrav     ldns_pkt_free(qpkt);
183*3fc9e2c3SDag-Erling Smørgrav 
184*3fc9e2c3SDag-Erling Smørgrav     ldns_resolver_set_nameservers(res, ns);
185*3fc9e2c3SDag-Erling Smørgrav     ldns_resolver_set_rtt(res, rtt);
186*3fc9e2c3SDag-Erling Smørgrav     ldns_resolver_set_nameserver_count(res, nscnt);
187*3fc9e2c3SDag-Erling Smørgrav     return status;
188*3fc9e2c3SDag-Erling Smørgrav }
189*3fc9e2c3SDag-Erling Smørgrav 
190*3fc9e2c3SDag-Erling Smørgrav static void
191*3fc9e2c3SDag-Erling Smørgrav ldns_pkt_filter_answer(ldns_pkt *pkt, ldns_rr_type type) {
192*3fc9e2c3SDag-Erling Smørgrav     int i, j, cnt;
193*3fc9e2c3SDag-Erling Smørgrav     ldns_rr_list *rrlist;
194*3fc9e2c3SDag-Erling Smørgrav     ldns_rr *rr;
195*3fc9e2c3SDag-Erling Smørgrav     ldns_rr_type rrtype;
196*3fc9e2c3SDag-Erling Smørgrav 
197*3fc9e2c3SDag-Erling Smørgrav     rrlist = ldns_pkt_answer(pkt);
198*3fc9e2c3SDag-Erling Smørgrav     cnt = ldns_rr_list_rr_count(rrlist);
199*3fc9e2c3SDag-Erling Smørgrav     for (i = j = 0; i < cnt; i++) {
200*3fc9e2c3SDag-Erling Smørgrav         rr = ldns_rr_list_rr(rrlist, i);
201*3fc9e2c3SDag-Erling Smørgrav         rrtype = ldns_rr_get_type(rr);
202*3fc9e2c3SDag-Erling Smørgrav         if (type == LDNS_RR_TYPE_ANY ||
203*3fc9e2c3SDag-Erling Smørgrav             type == rrtype ||
204*3fc9e2c3SDag-Erling Smørgrav             (type == LDNS_RR_TYPE_AXFR &&
205*3fc9e2c3SDag-Erling Smørgrav                 (rrtype == LDNS_RR_TYPE_A ||
206*3fc9e2c3SDag-Erling Smørgrav 		    rrtype == LDNS_RR_TYPE_AAAA ||
207*3fc9e2c3SDag-Erling Smørgrav 		    rrtype == LDNS_RR_TYPE_NS ||
208*3fc9e2c3SDag-Erling Smørgrav 		    rrtype == LDNS_RR_TYPE_PTR)))
209*3fc9e2c3SDag-Erling Smørgrav             ldns_rr_list_set_rr(rrlist, rr, j++);
210*3fc9e2c3SDag-Erling Smørgrav     }
211*3fc9e2c3SDag-Erling Smørgrav     ldns_rr_list_set_rr_count(rrlist, j);
212*3fc9e2c3SDag-Erling Smørgrav }
213*3fc9e2c3SDag-Erling Smørgrav 
214*3fc9e2c3SDag-Erling Smørgrav /* Packet content printing.
215*3fc9e2c3SDag-Erling Smørgrav  */
216*3fc9e2c3SDag-Erling Smørgrav 
217*3fc9e2c3SDag-Erling Smørgrav static struct {
218*3fc9e2c3SDag-Erling Smørgrav     ldns_rr_type type;
219*3fc9e2c3SDag-Erling Smørgrav     const char *text;
220*3fc9e2c3SDag-Erling Smørgrav } rr_types[] = {
221*3fc9e2c3SDag-Erling Smørgrav     {LDNS_RR_TYPE_A,        "has address"},
222*3fc9e2c3SDag-Erling Smørgrav     {LDNS_RR_TYPE_NS,       "name server"},
223*3fc9e2c3SDag-Erling Smørgrav     {LDNS_RR_TYPE_CNAME,    "is an alias for"},
224*3fc9e2c3SDag-Erling Smørgrav     {LDNS_RR_TYPE_WKS,      "has well known services"},
225*3fc9e2c3SDag-Erling Smørgrav     {LDNS_RR_TYPE_PTR,      "domain name pointer"},
226*3fc9e2c3SDag-Erling Smørgrav     {LDNS_RR_TYPE_HINFO,    "host information"},
227*3fc9e2c3SDag-Erling Smørgrav     {LDNS_RR_TYPE_MX,       "mail is handled by"},
228*3fc9e2c3SDag-Erling Smørgrav     {LDNS_RR_TYPE_TXT,      "descriptive text"},
229*3fc9e2c3SDag-Erling Smørgrav     {LDNS_RR_TYPE_X25,      "x25 address"},
230*3fc9e2c3SDag-Erling Smørgrav     {LDNS_RR_TYPE_ISDN,     "ISDN address"},
231*3fc9e2c3SDag-Erling Smørgrav     {LDNS_RR_TYPE_SIG,      "has signature"},
232*3fc9e2c3SDag-Erling Smørgrav     {LDNS_RR_TYPE_KEY,      "has key"},
233*3fc9e2c3SDag-Erling Smørgrav     {LDNS_RR_TYPE_AAAA,     "has IPv6 address"},
234*3fc9e2c3SDag-Erling Smørgrav     {LDNS_RR_TYPE_LOC,      "location"},
235*3fc9e2c3SDag-Erling Smørgrav };
236*3fc9e2c3SDag-Erling Smørgrav 
237*3fc9e2c3SDag-Erling Smørgrav static void
238*3fc9e2c3SDag-Erling Smørgrav print_opcode(ldns_pkt_opcode opcode) {
239*3fc9e2c3SDag-Erling Smørgrav     ldns_lookup_table *lt = ldns_lookup_by_id(ldns_opcodes, opcode);
240*3fc9e2c3SDag-Erling Smørgrav 
241*3fc9e2c3SDag-Erling Smørgrav     if (lt && lt->name)
242*3fc9e2c3SDag-Erling Smørgrav         printf("%s", lt->name);
243*3fc9e2c3SDag-Erling Smørgrav     else
244*3fc9e2c3SDag-Erling Smørgrav         printf("RESERVED%d", opcode);
245*3fc9e2c3SDag-Erling Smørgrav }
246*3fc9e2c3SDag-Erling Smørgrav 
247*3fc9e2c3SDag-Erling Smørgrav static void
248*3fc9e2c3SDag-Erling Smørgrav print_rcode(uint8_t rcode) {
249*3fc9e2c3SDag-Erling Smørgrav     ldns_lookup_table *lt = ldns_lookup_by_id(ldns_rcodes, rcode);
250*3fc9e2c3SDag-Erling Smørgrav 
251*3fc9e2c3SDag-Erling Smørgrav     if (lt && lt->name)
252*3fc9e2c3SDag-Erling Smørgrav         printf("%s", lt->name);
253*3fc9e2c3SDag-Erling Smørgrav     else
254*3fc9e2c3SDag-Erling Smørgrav         printf("RESERVED%d", rcode);
255*3fc9e2c3SDag-Erling Smørgrav }
256*3fc9e2c3SDag-Erling Smørgrav 
257*3fc9e2c3SDag-Erling Smørgrav static int
258*3fc9e2c3SDag-Erling Smørgrav print_rr_type(ldns_rr_type type) {
259*3fc9e2c3SDag-Erling Smørgrav     char *str;
260*3fc9e2c3SDag-Erling Smørgrav     int n;
261*3fc9e2c3SDag-Erling Smørgrav 
262*3fc9e2c3SDag-Erling Smørgrav     str = ldns_rr_type2str(type);
263*3fc9e2c3SDag-Erling Smørgrav     n = printf("%s", str);
264*3fc9e2c3SDag-Erling Smørgrav     free(str);
265*3fc9e2c3SDag-Erling Smørgrav     return n;
266*3fc9e2c3SDag-Erling Smørgrav }
267*3fc9e2c3SDag-Erling Smørgrav 
268*3fc9e2c3SDag-Erling Smørgrav static int
269*3fc9e2c3SDag-Erling Smørgrav print_rr_class(ldns_rr_class cls) {
270*3fc9e2c3SDag-Erling Smørgrav     char *str;
271*3fc9e2c3SDag-Erling Smørgrav     int n;
272*3fc9e2c3SDag-Erling Smørgrav 
273*3fc9e2c3SDag-Erling Smørgrav     str = ldns_rr_class2str(cls);
274*3fc9e2c3SDag-Erling Smørgrav     n = printf("%s", str);
275*3fc9e2c3SDag-Erling Smørgrav     free(str);
276*3fc9e2c3SDag-Erling Smørgrav     return n;
277*3fc9e2c3SDag-Erling Smørgrav }
278*3fc9e2c3SDag-Erling Smørgrav 
279*3fc9e2c3SDag-Erling Smørgrav static int
280*3fc9e2c3SDag-Erling Smørgrav print_rdf(ldns_rdf *rdf) {
281*3fc9e2c3SDag-Erling Smørgrav     char *str;
282*3fc9e2c3SDag-Erling Smørgrav     int n;
283*3fc9e2c3SDag-Erling Smørgrav 
284*3fc9e2c3SDag-Erling Smørgrav     str = ldns_rdf2str(rdf);
285*3fc9e2c3SDag-Erling Smørgrav     n = printf("%s", str);
286*3fc9e2c3SDag-Erling Smørgrav     free(str);
287*3fc9e2c3SDag-Erling Smørgrav     return n;
288*3fc9e2c3SDag-Erling Smørgrav }
289*3fc9e2c3SDag-Erling Smørgrav 
290*3fc9e2c3SDag-Erling Smørgrav static int
291*3fc9e2c3SDag-Erling Smørgrav print_rdf_nodot(ldns_rdf *rdf) {
292*3fc9e2c3SDag-Erling Smørgrav     char *str;
293*3fc9e2c3SDag-Erling Smørgrav     int len, n;
294*3fc9e2c3SDag-Erling Smørgrav 
295*3fc9e2c3SDag-Erling Smørgrav     str = ldns_rdf2str(rdf);
296*3fc9e2c3SDag-Erling Smørgrav     len = strlen(str);
297*3fc9e2c3SDag-Erling Smørgrav     n = printf("%.*s", str[len-1] == '.' ? len-1 : len, str);
298*3fc9e2c3SDag-Erling Smørgrav     free(str);
299*3fc9e2c3SDag-Erling Smørgrav     return n;
300*3fc9e2c3SDag-Erling Smørgrav }
301*3fc9e2c3SDag-Erling Smørgrav 
302*3fc9e2c3SDag-Erling Smørgrav static int
303*3fc9e2c3SDag-Erling Smørgrav print_padding(int fromcol, int tocol) {
304*3fc9e2c3SDag-Erling Smørgrav     int col = fromcol, nextcol = fromcol + 8 - fromcol%8;
305*3fc9e2c3SDag-Erling Smørgrav 
306*3fc9e2c3SDag-Erling Smørgrav     if (fromcol + 1 > tocol) tocol = fromcol + 1;
307*3fc9e2c3SDag-Erling Smørgrav     for (; nextcol <= tocol; col = nextcol, nextcol += 8)
308*3fc9e2c3SDag-Erling Smørgrav         printf("\t");
309*3fc9e2c3SDag-Erling Smørgrav     for (; col < tocol; col++)
310*3fc9e2c3SDag-Erling Smørgrav         printf(" ");
311*3fc9e2c3SDag-Erling Smørgrav     return col - fromcol;
312*3fc9e2c3SDag-Erling Smørgrav }
313*3fc9e2c3SDag-Erling Smørgrav 
314*3fc9e2c3SDag-Erling Smørgrav static void
315*3fc9e2c3SDag-Erling Smørgrav print_rr_verbose(ldns_rr *rr) {
316*3fc9e2c3SDag-Erling Smørgrav     bool isq = ldns_rr_is_question(rr);
317*3fc9e2c3SDag-Erling Smørgrav     int rdcnt = ldns_rr_rd_count(rr);
318*3fc9e2c3SDag-Erling Smørgrav     int i, n;
319*3fc9e2c3SDag-Erling Smørgrav 
320*3fc9e2c3SDag-Erling Smørgrav     /* bind9-host does not count the initial ';' here */
321*3fc9e2c3SDag-Erling Smørgrav     n = isq ? printf(";") : 0;
322*3fc9e2c3SDag-Erling Smørgrav     n = print_rdf(ldns_rr_owner(rr));
323*3fc9e2c3SDag-Erling Smørgrav     if (!isq) {
324*3fc9e2c3SDag-Erling Smørgrav         n += print_padding(n, 24);
325*3fc9e2c3SDag-Erling Smørgrav         n += printf("%d", ldns_rr_ttl(rr));
326*3fc9e2c3SDag-Erling Smørgrav     }
327*3fc9e2c3SDag-Erling Smørgrav     n += print_padding(n, 32);
328*3fc9e2c3SDag-Erling Smørgrav     n += print_rr_class(ldns_rr_get_class(rr));
329*3fc9e2c3SDag-Erling Smørgrav     n += print_padding(n, 40);
330*3fc9e2c3SDag-Erling Smørgrav     n += print_rr_type(ldns_rr_get_type(rr));
331*3fc9e2c3SDag-Erling Smørgrav     for (i = 0; i < rdcnt; i++) {
332*3fc9e2c3SDag-Erling Smørgrav         if (i == 0) print_padding(n, 48);
333*3fc9e2c3SDag-Erling Smørgrav         else printf(" ");
334*3fc9e2c3SDag-Erling Smørgrav         print_rdf(ldns_rr_rdf(rr, i));
335*3fc9e2c3SDag-Erling Smørgrav     }
336*3fc9e2c3SDag-Erling Smørgrav     printf("\n");
337*3fc9e2c3SDag-Erling Smørgrav }
338*3fc9e2c3SDag-Erling Smørgrav 
339*3fc9e2c3SDag-Erling Smørgrav static void
340*3fc9e2c3SDag-Erling Smørgrav print_pkt_section_verbose(const char *name, ldns_rr_list *rrlist) {
341*3fc9e2c3SDag-Erling Smørgrav     int i, cnt = ldns_rr_list_rr_count(rrlist);
342*3fc9e2c3SDag-Erling Smørgrav 
343*3fc9e2c3SDag-Erling Smørgrav     if (cnt == 0)
344*3fc9e2c3SDag-Erling Smørgrav         return;
345*3fc9e2c3SDag-Erling Smørgrav     printf(";; %s SECTION:\n", name);
346*3fc9e2c3SDag-Erling Smørgrav     for (i = 0; i < cnt; i++)
347*3fc9e2c3SDag-Erling Smørgrav         print_rr_verbose(ldns_rr_list_rr(rrlist, i));
348*3fc9e2c3SDag-Erling Smørgrav     printf("\n");
349*3fc9e2c3SDag-Erling Smørgrav }
350*3fc9e2c3SDag-Erling Smørgrav 
351*3fc9e2c3SDag-Erling Smørgrav static void
352*3fc9e2c3SDag-Erling Smørgrav print_pkt_verbose(ldns_pkt *pkt) {
353*3fc9e2c3SDag-Erling Smørgrav     int got_flags = 0;
354*3fc9e2c3SDag-Erling Smørgrav 
355*3fc9e2c3SDag-Erling Smørgrav     printf(";; ->>HEADER<<- opcode: ");
356*3fc9e2c3SDag-Erling Smørgrav     print_opcode(ldns_pkt_get_opcode(pkt));
357*3fc9e2c3SDag-Erling Smørgrav     printf(", status: ");
358*3fc9e2c3SDag-Erling Smørgrav     print_rcode(ldns_pkt_get_rcode(pkt));
359*3fc9e2c3SDag-Erling Smørgrav     printf(", id: %u\n", ldns_pkt_id(pkt));
360*3fc9e2c3SDag-Erling Smørgrav     printf(";; flags:");
361*3fc9e2c3SDag-Erling Smørgrav     if (ldns_pkt_qr(pkt)) printf(" qr"), got_flags = 1;
362*3fc9e2c3SDag-Erling Smørgrav     if (ldns_pkt_aa(pkt)) printf(" aa"), got_flags = 1;
363*3fc9e2c3SDag-Erling Smørgrav     if (ldns_pkt_tc(pkt)) printf(" tc"), got_flags = 1;
364*3fc9e2c3SDag-Erling Smørgrav     if (ldns_pkt_rd(pkt)) printf(" rd"), got_flags = 1;
365*3fc9e2c3SDag-Erling Smørgrav     if (ldns_pkt_ra(pkt)) printf(" ra"), got_flags = 1;
366*3fc9e2c3SDag-Erling Smørgrav     if (ldns_pkt_ad(pkt)) printf(" ad"), got_flags = 1;
367*3fc9e2c3SDag-Erling Smørgrav     if (ldns_pkt_cd(pkt)) printf(" cd"), got_flags = 1;
368*3fc9e2c3SDag-Erling Smørgrav     if (!got_flags) printf(" ");
369*3fc9e2c3SDag-Erling Smørgrav     printf("; QUERY: %u, ANSWER: %u, AUTHORITY: %u, ADDITIONAL: %u\n",
370*3fc9e2c3SDag-Erling Smørgrav         ldns_pkt_qdcount(pkt), ldns_pkt_ancount(pkt),
371*3fc9e2c3SDag-Erling Smørgrav         ldns_pkt_nscount(pkt), ldns_pkt_arcount(pkt));
372*3fc9e2c3SDag-Erling Smørgrav     if (ldns_pkt_edns(pkt))
373*3fc9e2c3SDag-Erling Smørgrav         printf(";; EDNS: version: %u, udp=%u\n",
374*3fc9e2c3SDag-Erling Smørgrav             ldns_pkt_edns_version(pkt), ldns_pkt_edns_udp_size(pkt));
375*3fc9e2c3SDag-Erling Smørgrav     printf("\n");
376*3fc9e2c3SDag-Erling Smørgrav     print_pkt_section_verbose("QUESTION", ldns_pkt_question(pkt));
377*3fc9e2c3SDag-Erling Smørgrav     print_pkt_section_verbose("ANSWER", ldns_pkt_answer(pkt));
378*3fc9e2c3SDag-Erling Smørgrav     print_pkt_section_verbose("AUTHORITY", ldns_pkt_authority(pkt));
379*3fc9e2c3SDag-Erling Smørgrav     print_pkt_section_verbose("ADDITIONAL", ldns_pkt_additional(pkt));
380*3fc9e2c3SDag-Erling Smørgrav }
381*3fc9e2c3SDag-Erling Smørgrav 
382*3fc9e2c3SDag-Erling Smørgrav static void
383*3fc9e2c3SDag-Erling Smørgrav print_rr_short(ldns_rr *rr) {
384*3fc9e2c3SDag-Erling Smørgrav     ldns_rr_type type = ldns_rr_get_type(rr);
385*3fc9e2c3SDag-Erling Smørgrav     size_t i, rdcnt = ldns_rr_rd_count(rr);
386*3fc9e2c3SDag-Erling Smørgrav 
387*3fc9e2c3SDag-Erling Smørgrav     print_rdf_nodot(ldns_rr_owner(rr));
388*3fc9e2c3SDag-Erling Smørgrav     printf(" ");
389*3fc9e2c3SDag-Erling Smørgrav     for (i = 0; i < countof(rr_types); i++) {
390*3fc9e2c3SDag-Erling Smørgrav         if (rr_types[i].type == type) {
391*3fc9e2c3SDag-Erling Smørgrav             printf("%s", rr_types[i].text);
392*3fc9e2c3SDag-Erling Smørgrav             goto found;
393*3fc9e2c3SDag-Erling Smørgrav         }
394*3fc9e2c3SDag-Erling Smørgrav     }
395*3fc9e2c3SDag-Erling Smørgrav 
396*3fc9e2c3SDag-Erling Smørgrav     printf("has ");
397*3fc9e2c3SDag-Erling Smørgrav     print_rr_type(type);
398*3fc9e2c3SDag-Erling Smørgrav     printf(" record");
399*3fc9e2c3SDag-Erling Smørgrav 
400*3fc9e2c3SDag-Erling Smørgrav found:
401*3fc9e2c3SDag-Erling Smørgrav     for (i = 0; i < rdcnt; i++) {
402*3fc9e2c3SDag-Erling Smørgrav         printf(" ");
403*3fc9e2c3SDag-Erling Smørgrav         print_rdf(ldns_rr_rdf(rr, i));
404*3fc9e2c3SDag-Erling Smørgrav     }
405*3fc9e2c3SDag-Erling Smørgrav     printf("\n");
406*3fc9e2c3SDag-Erling Smørgrav }
407*3fc9e2c3SDag-Erling Smørgrav 
408*3fc9e2c3SDag-Erling Smørgrav static void
409*3fc9e2c3SDag-Erling Smørgrav print_pkt_short(ldns_pkt *pkt, bool print_rr_server) {
410*3fc9e2c3SDag-Erling Smørgrav     ldns_rr_list *rrlist = ldns_pkt_answer(pkt);
411*3fc9e2c3SDag-Erling Smørgrav     size_t i;
412*3fc9e2c3SDag-Erling Smørgrav 
413*3fc9e2c3SDag-Erling Smørgrav     for (i = 0; i < ldns_rr_list_rr_count(rrlist); i++) {
414*3fc9e2c3SDag-Erling Smørgrav         if (print_rr_server) {
415*3fc9e2c3SDag-Erling Smørgrav             printf("Nameserver ");
416*3fc9e2c3SDag-Erling Smørgrav             print_rdf(ldns_pkt_answerfrom(pkt));
417*3fc9e2c3SDag-Erling Smørgrav             printf(":\n\t");
418*3fc9e2c3SDag-Erling Smørgrav         }
419*3fc9e2c3SDag-Erling Smørgrav         print_rr_short(ldns_rr_list_rr(rrlist, i));
420*3fc9e2c3SDag-Erling Smørgrav     }
421*3fc9e2c3SDag-Erling Smørgrav }
422*3fc9e2c3SDag-Erling Smørgrav 
423*3fc9e2c3SDag-Erling Smørgrav static void
424*3fc9e2c3SDag-Erling Smørgrav print_received_line(ldns_resolver *res, ldns_pkt *pkt) {
425*3fc9e2c3SDag-Erling Smørgrav     char *from = ldns_rdf2str(ldns_pkt_answerfrom(pkt));
426*3fc9e2c3SDag-Erling Smørgrav 
427*3fc9e2c3SDag-Erling Smørgrav     printf("Received %zu bytes from %s#%d in %d ms\n",
428*3fc9e2c3SDag-Erling Smørgrav             ldns_pkt_size(pkt), from, ldns_resolver_port(res),
429*3fc9e2c3SDag-Erling Smørgrav             ldns_pkt_querytime(pkt));
430*3fc9e2c3SDag-Erling Smørgrav     free(from);
431*3fc9e2c3SDag-Erling Smørgrav }
432*3fc9e2c3SDag-Erling Smørgrav 
433*3fc9e2c3SDag-Erling Smørgrav /* Main program.
434*3fc9e2c3SDag-Erling Smørgrav  *
435*3fc9e2c3SDag-Erling Smørgrav  * Note that no memory is freed below this line by intention.
436*3fc9e2c3SDag-Erling Smørgrav  */
437*3fc9e2c3SDag-Erling Smørgrav 
438*3fc9e2c3SDag-Erling Smørgrav #define DEFAULT_TCP_TIMEOUT 10
439*3fc9e2c3SDag-Erling Smørgrav #define DEFAULT_UDP_TIMEOUT 5
440*3fc9e2c3SDag-Erling Smørgrav 
441*3fc9e2c3SDag-Erling Smørgrav enum operation_mode { M_AXFR, M_DEFAULT_Q, M_SINGLE_Q, M_SOA };
442*3fc9e2c3SDag-Erling Smørgrav 
443*3fc9e2c3SDag-Erling Smørgrav static enum operation_mode o_mode = M_DEFAULT_Q;
444*3fc9e2c3SDag-Erling Smørgrav static bool o_ignore_servfail = true;
445*3fc9e2c3SDag-Erling Smørgrav static bool o_ip6_int = false;
446*3fc9e2c3SDag-Erling Smørgrav static bool o_print_pkt_server = false;
447*3fc9e2c3SDag-Erling Smørgrav static bool o_print_rr_server = false;
448*3fc9e2c3SDag-Erling Smørgrav static bool o_recursive = true;
449*3fc9e2c3SDag-Erling Smørgrav static bool o_tcp = false;
450*3fc9e2c3SDag-Erling Smørgrav static bool o_verbose = false;
451*3fc9e2c3SDag-Erling Smørgrav static char *o_name = NULL;
452*3fc9e2c3SDag-Erling Smørgrav static char *o_server = NULL;
453*3fc9e2c3SDag-Erling Smørgrav static int o_ipversion = LDNS_RESOLV_INETANY;
454*3fc9e2c3SDag-Erling Smørgrav static int o_ndots = 1;
455*3fc9e2c3SDag-Erling Smørgrav static int o_retries = 1;
456*3fc9e2c3SDag-Erling Smørgrav static ldns_rr_class o_rrclass = LDNS_RR_CLASS_IN;
457*3fc9e2c3SDag-Erling Smørgrav static ldns_rr_type o_rrtype = LDNS_RR_TYPE_A;
458*3fc9e2c3SDag-Erling Smørgrav static time_t o_timeout = 0;
459*3fc9e2c3SDag-Erling Smørgrav static uint32_t o_ixfr_serial = 0;
460*3fc9e2c3SDag-Erling Smørgrav 
461*3fc9e2c3SDag-Erling Smørgrav static void
462*3fc9e2c3SDag-Erling Smørgrav usage(void) {
463*3fc9e2c3SDag-Erling Smørgrav     fputs(
464*3fc9e2c3SDag-Erling Smørgrav     "Usage: host [-aCdilrsTvw46] [-c class] [-N ndots] [-R number]\n"
465*3fc9e2c3SDag-Erling Smørgrav     "            [-t type] [-W wait] name [server]\n"
466*3fc9e2c3SDag-Erling Smørgrav     "\t-a same as -v -t ANY\n"
467*3fc9e2c3SDag-Erling Smørgrav     "\t-C query SOA records from all authoritative name servers\n"
468*3fc9e2c3SDag-Erling Smørgrav     "\t-c use this query class (IN, CH, HS, etc)\n"
469*3fc9e2c3SDag-Erling Smørgrav     "\t-d produce verbose output, same as -v\n"
470*3fc9e2c3SDag-Erling Smørgrav     "\t-i use IP6.INT for IPv6 reverse lookups\n"
471*3fc9e2c3SDag-Erling Smørgrav     "\t-l list records in a zone via AXFR\n"
472*3fc9e2c3SDag-Erling Smørgrav     "\t-N consider names with at least this many dots as absolute\n"
473*3fc9e2c3SDag-Erling Smørgrav     "\t-R retry UDP queries this many times\n"
474*3fc9e2c3SDag-Erling Smørgrav     "\t-r disable recursive query\n"
475*3fc9e2c3SDag-Erling Smørgrav     "\t-s do not ignore SERVFAIL responses\n"
476*3fc9e2c3SDag-Erling Smørgrav     "\t-T send query via TCP\n"
477*3fc9e2c3SDag-Erling Smørgrav     "\t-t use this query type (A, AAAA, MX, etc)\n"
478*3fc9e2c3SDag-Erling Smørgrav     "\t-v produce verbose output\n"
479*3fc9e2c3SDag-Erling Smørgrav     "\t-w wait forever for a server reply\n"
480*3fc9e2c3SDag-Erling Smørgrav     "\t-W wait this many seconds for a reply\n"
481*3fc9e2c3SDag-Erling Smørgrav     "\t-4 use IPv4 only\n"
482*3fc9e2c3SDag-Erling Smørgrav     "\t-6 use IPv6 only\n",
483*3fc9e2c3SDag-Erling Smørgrav     stderr);
484*3fc9e2c3SDag-Erling Smørgrav     exit(1);
485*3fc9e2c3SDag-Erling Smørgrav }
486*3fc9e2c3SDag-Erling Smørgrav 
487*3fc9e2c3SDag-Erling Smørgrav static void
488*3fc9e2c3SDag-Erling Smørgrav parse_args(int argc, char *argv[]) {
489*3fc9e2c3SDag-Erling Smørgrav     int ch;
490*3fc9e2c3SDag-Erling Smørgrav 
491*3fc9e2c3SDag-Erling Smørgrav     progname = argv[0];
492*3fc9e2c3SDag-Erling Smørgrav     while ((ch = getopt(argc, argv, "aCdilrsTvw46c:N:R:t:W:")) != -1) {
493*3fc9e2c3SDag-Erling Smørgrav         switch (ch) {
494*3fc9e2c3SDag-Erling Smørgrav         case 'a':
495*3fc9e2c3SDag-Erling Smørgrav             if (o_mode != M_AXFR)
496*3fc9e2c3SDag-Erling Smørgrav                 o_mode = M_SINGLE_Q;
497*3fc9e2c3SDag-Erling Smørgrav             o_rrtype = LDNS_RR_TYPE_ANY;
498*3fc9e2c3SDag-Erling Smørgrav             o_verbose = true;
499*3fc9e2c3SDag-Erling Smørgrav             break;
500*3fc9e2c3SDag-Erling Smørgrav         case 'C':
501*3fc9e2c3SDag-Erling Smørgrav             o_mode = M_SOA;
502*3fc9e2c3SDag-Erling Smørgrav             o_print_rr_server = true;
503*3fc9e2c3SDag-Erling Smørgrav             o_rrclass = LDNS_RR_CLASS_IN;
504*3fc9e2c3SDag-Erling Smørgrav             o_rrtype = LDNS_RR_TYPE_NS;
505*3fc9e2c3SDag-Erling Smørgrav             break;
506*3fc9e2c3SDag-Erling Smørgrav         case 'c':
507*3fc9e2c3SDag-Erling Smørgrav             /* bind9-host sets o_mode to M_SINGLE_Q here */
508*3fc9e2c3SDag-Erling Smørgrav             o_rrclass = ldns_get_rr_class_by_name(optarg);
509*3fc9e2c3SDag-Erling Smørgrav             if (o_rrclass <= 0)
510*3fc9e2c3SDag-Erling Smørgrav                 die(2, "invalid class: %s\n", optarg);
511*3fc9e2c3SDag-Erling Smørgrav             break;
512*3fc9e2c3SDag-Erling Smørgrav         case 'd': o_verbose = true; break;
513*3fc9e2c3SDag-Erling Smørgrav         case 'i': o_ip6_int = true; break;
514*3fc9e2c3SDag-Erling Smørgrav         case 'l':
515*3fc9e2c3SDag-Erling Smørgrav             o_mode = M_AXFR;
516*3fc9e2c3SDag-Erling Smørgrav             o_rrtype = LDNS_RR_TYPE_AXFR;
517*3fc9e2c3SDag-Erling Smørgrav             o_tcp = true;
518*3fc9e2c3SDag-Erling Smørgrav             break;
519*3fc9e2c3SDag-Erling Smørgrav         case 'N':
520*3fc9e2c3SDag-Erling Smørgrav             o_ndots = atoi(optarg);
521*3fc9e2c3SDag-Erling Smørgrav             if (o_ndots < 0) o_ndots = 0;
522*3fc9e2c3SDag-Erling Smørgrav             break;
523*3fc9e2c3SDag-Erling Smørgrav         case 'n':
524*3fc9e2c3SDag-Erling Smørgrav             /* bind9-host accepts and ignores this option */
525*3fc9e2c3SDag-Erling Smørgrav             break;
526*3fc9e2c3SDag-Erling Smørgrav         case 'r': o_recursive = 0; break;
527*3fc9e2c3SDag-Erling Smørgrav         case 'R':
528*3fc9e2c3SDag-Erling Smørgrav             o_retries = atoi(optarg);
529*3fc9e2c3SDag-Erling Smørgrav             if (o_retries <= 0) o_retries = 1;
530*3fc9e2c3SDag-Erling Smørgrav             if (o_retries > 255) o_retries = 255;
531*3fc9e2c3SDag-Erling Smørgrav             break;
532*3fc9e2c3SDag-Erling Smørgrav         case 's': o_ignore_servfail = false; break;
533*3fc9e2c3SDag-Erling Smørgrav         case 'T': o_tcp = true; break;
534*3fc9e2c3SDag-Erling Smørgrav         case 't':
535*3fc9e2c3SDag-Erling Smørgrav             if (o_mode != M_AXFR)
536*3fc9e2c3SDag-Erling Smørgrav                 o_mode = M_SINGLE_Q;
537*3fc9e2c3SDag-Erling Smørgrav             if (strncasecmp(optarg, "ixfr=", 5) == 0) {
538*3fc9e2c3SDag-Erling Smørgrav                 o_rrtype = LDNS_RR_TYPE_IXFR;
539*3fc9e2c3SDag-Erling Smørgrav                 o_ixfr_serial = atol(optarg + 5);
540*3fc9e2c3SDag-Erling Smørgrav             } else {
541*3fc9e2c3SDag-Erling Smørgrav                 o_rrtype = ldns_get_rr_type_by_name(optarg);
542*3fc9e2c3SDag-Erling Smørgrav                 if (o_rrtype <= 0)
543*3fc9e2c3SDag-Erling Smørgrav                     die(2, "invalid type: %s\n", optarg);
544*3fc9e2c3SDag-Erling Smørgrav             }
545*3fc9e2c3SDag-Erling Smørgrav             if (o_rrtype == LDNS_RR_TYPE_AXFR || o_rrtype == LDNS_RR_TYPE_IXFR)
546*3fc9e2c3SDag-Erling Smørgrav                 o_tcp = true;
547*3fc9e2c3SDag-Erling Smørgrav             if (o_rrtype == LDNS_RR_TYPE_AXFR) {
548*3fc9e2c3SDag-Erling Smørgrav                 o_mode = M_AXFR;
549*3fc9e2c3SDag-Erling Smørgrav                 o_rrtype = LDNS_RR_TYPE_ANY;
550*3fc9e2c3SDag-Erling Smørgrav                 o_verbose = true;
551*3fc9e2c3SDag-Erling Smørgrav             }
552*3fc9e2c3SDag-Erling Smørgrav             break;
553*3fc9e2c3SDag-Erling Smørgrav         case 'v': o_verbose = true; break;
554*3fc9e2c3SDag-Erling Smørgrav         case 'w':
555*3fc9e2c3SDag-Erling Smørgrav               o_timeout = (time_t)INT_MAX;
556*3fc9e2c3SDag-Erling Smørgrav               break;
557*3fc9e2c3SDag-Erling Smørgrav         case 'W':
558*3fc9e2c3SDag-Erling Smørgrav             o_timeout = atol(optarg);
559*3fc9e2c3SDag-Erling Smørgrav             if (o_timeout <= 0) o_timeout = 1;
560*3fc9e2c3SDag-Erling Smørgrav             break;
561*3fc9e2c3SDag-Erling Smørgrav         case '4': o_ipversion = LDNS_RESOLV_INET; break;
562*3fc9e2c3SDag-Erling Smørgrav         case '6': o_ipversion = LDNS_RESOLV_INET6; break;
563*3fc9e2c3SDag-Erling Smørgrav         default:
564*3fc9e2c3SDag-Erling Smørgrav             usage();
565*3fc9e2c3SDag-Erling Smørgrav         }
566*3fc9e2c3SDag-Erling Smørgrav     }
567*3fc9e2c3SDag-Erling Smørgrav     argc -= optind;
568*3fc9e2c3SDag-Erling Smørgrav     argv += optind;
569*3fc9e2c3SDag-Erling Smørgrav     /* bind9-host ignores arguments after the 2-nd one */
570*3fc9e2c3SDag-Erling Smørgrav     if (argc < 1)
571*3fc9e2c3SDag-Erling Smørgrav         usage();
572*3fc9e2c3SDag-Erling Smørgrav     o_name = argv[0];
573*3fc9e2c3SDag-Erling Smørgrav     if (argc > 1) {
574*3fc9e2c3SDag-Erling Smørgrav         o_server = argv[1];
575*3fc9e2c3SDag-Erling Smørgrav         o_print_pkt_server = true;
576*3fc9e2c3SDag-Erling Smørgrav     }
577*3fc9e2c3SDag-Erling Smørgrav }
578*3fc9e2c3SDag-Erling Smørgrav 
579*3fc9e2c3SDag-Erling Smørgrav static ldns_rdf*
580*3fc9e2c3SDag-Erling Smørgrav safe_str2rdf_dname(const char *name) {
581*3fc9e2c3SDag-Erling Smørgrav     ldns_rdf *dname;
582*3fc9e2c3SDag-Erling Smørgrav     ldns_status status;
583*3fc9e2c3SDag-Erling Smørgrav 
584*3fc9e2c3SDag-Erling Smørgrav     if ((status = ldns_str2rdf_dname(&dname, name)) != LDNS_STATUS_OK) {
585*3fc9e2c3SDag-Erling Smørgrav         die(1, "'%s' is not a legal name (%s)",
586*3fc9e2c3SDag-Erling Smørgrav             name, ldns_get_errorstr_by_id(status));
587*3fc9e2c3SDag-Erling Smørgrav     }
588*3fc9e2c3SDag-Erling Smørgrav     return dname;
589*3fc9e2c3SDag-Erling Smørgrav }
590*3fc9e2c3SDag-Erling Smørgrav 
591*3fc9e2c3SDag-Erling Smørgrav static ldns_rdf*
592*3fc9e2c3SDag-Erling Smørgrav safe_dname_cat_clone(const ldns_rdf *rd1, const ldns_rdf *rd2) {
593*3fc9e2c3SDag-Erling Smørgrav     ldns_rdf *result = ldns_dname_cat_clone(rd1, rd2);
594*3fc9e2c3SDag-Erling Smørgrav 
595*3fc9e2c3SDag-Erling Smørgrav     if (!result)
596*3fc9e2c3SDag-Erling Smørgrav         die(1, "not enought memory for a domain name");
597*3fc9e2c3SDag-Erling Smørgrav     /* Why doesn't ldns_dname_cat_clone check this condition? */
598*3fc9e2c3SDag-Erling Smørgrav     if (ldns_rdf_size(result) > LDNS_MAX_DOMAINLEN)
599*3fc9e2c3SDag-Erling Smørgrav         die(1, "'%s' is not a legal name (%s)\n", ldns_rdf2str(result),
600*3fc9e2c3SDag-Erling Smørgrav             ldns_get_errorstr_by_id(LDNS_STATUS_DOMAINNAME_OVERFLOW));
601*3fc9e2c3SDag-Erling Smørgrav     return result;
602*3fc9e2c3SDag-Erling Smørgrav }
603*3fc9e2c3SDag-Erling Smørgrav 
604*3fc9e2c3SDag-Erling Smørgrav static bool
605*3fc9e2c3SDag-Erling Smørgrav query(ldns_resolver *res, ldns_rdf *domain, ldns_pkt **pkt) {
606*3fc9e2c3SDag-Erling Smørgrav     ldns_status status;
607*3fc9e2c3SDag-Erling Smørgrav     ldns_pkt_rcode rcode;
608*3fc9e2c3SDag-Erling Smørgrav     int i, cnt;
609*3fc9e2c3SDag-Erling Smørgrav 
610*3fc9e2c3SDag-Erling Smørgrav     if (o_verbose) {
611*3fc9e2c3SDag-Erling Smørgrav         printf("Trying \"");
612*3fc9e2c3SDag-Erling Smørgrav         print_rdf_nodot(domain);
613*3fc9e2c3SDag-Erling Smørgrav         printf("\"\n");
614*3fc9e2c3SDag-Erling Smørgrav     }
615*3fc9e2c3SDag-Erling Smørgrav     for (cnt = ldns_resolver_nameserver_count(res), i = 0; i < cnt; i++) {
616*3fc9e2c3SDag-Erling Smørgrav         status = ldns_resolver_send_to(pkt, res, domain, o_rrtype,
617*3fc9e2c3SDag-Erling Smørgrav             o_rrclass, o_recursive ? LDNS_RD : 0, o_ixfr_serial, i);
618*3fc9e2c3SDag-Erling Smørgrav         if (status != LDNS_STATUS_OK) {
619*3fc9e2c3SDag-Erling Smørgrav             *pkt = NULL;
620*3fc9e2c3SDag-Erling Smørgrav             continue;
621*3fc9e2c3SDag-Erling Smørgrav         }
622*3fc9e2c3SDag-Erling Smørgrav         if (ldns_pkt_tc(*pkt) && !ldns_resolver_usevc(res)) {
623*3fc9e2c3SDag-Erling Smørgrav             if (o_verbose)
624*3fc9e2c3SDag-Erling Smørgrav                 printf(";; Truncated, retrying in TCP mode.\n");
625*3fc9e2c3SDag-Erling Smørgrav             ldns_resolver_set_usevc(res, true);
626*3fc9e2c3SDag-Erling Smørgrav             status = ldns_resolver_send_to(pkt, res, domain, o_rrtype,
627*3fc9e2c3SDag-Erling Smørgrav                 o_rrclass, o_recursive ? LDNS_RD : 0, o_ixfr_serial, i);
628*3fc9e2c3SDag-Erling Smørgrav             ldns_resolver_set_usevc(res, false);
629*3fc9e2c3SDag-Erling Smørgrav             if (status != LDNS_STATUS_OK)
630*3fc9e2c3SDag-Erling Smørgrav                 continue;
631*3fc9e2c3SDag-Erling Smørgrav         }
632*3fc9e2c3SDag-Erling Smørgrav         rcode = ldns_pkt_get_rcode(*pkt);
633*3fc9e2c3SDag-Erling Smørgrav         if (o_ignore_servfail && rcode == LDNS_RCODE_SERVFAIL && cnt > 1)
634*3fc9e2c3SDag-Erling Smørgrav             continue;
635*3fc9e2c3SDag-Erling Smørgrav         return rcode == LDNS_RCODE_NOERROR;
636*3fc9e2c3SDag-Erling Smørgrav     }
637*3fc9e2c3SDag-Erling Smørgrav     if (*pkt == NULL) {
638*3fc9e2c3SDag-Erling Smørgrav         printf(";; connection timed out; no servers could be reached\n");
639*3fc9e2c3SDag-Erling Smørgrav         exit(1);
640*3fc9e2c3SDag-Erling Smørgrav     }
641*3fc9e2c3SDag-Erling Smørgrav     return false;
642*3fc9e2c3SDag-Erling Smørgrav }
643*3fc9e2c3SDag-Erling Smørgrav 
644*3fc9e2c3SDag-Erling Smørgrav static ldns_rdf *
645*3fc9e2c3SDag-Erling Smørgrav search(ldns_resolver *res, ldns_rdf *domain, ldns_pkt **pkt, bool absolute) {
646*3fc9e2c3SDag-Erling Smørgrav     ldns_rdf *dname, **searchlist;
647*3fc9e2c3SDag-Erling Smørgrav     int i, n;
648*3fc9e2c3SDag-Erling Smørgrav 
649*3fc9e2c3SDag-Erling Smørgrav     if (absolute && query(res, domain, pkt))
650*3fc9e2c3SDag-Erling Smørgrav         return domain;
651*3fc9e2c3SDag-Erling Smørgrav 
652*3fc9e2c3SDag-Erling Smørgrav     if ((dname = ldns_resolver_domain(res)) != NULL) {
653*3fc9e2c3SDag-Erling Smørgrav         dname = safe_dname_cat_clone(domain, dname);
654*3fc9e2c3SDag-Erling Smørgrav         if (query(res, dname, pkt))
655*3fc9e2c3SDag-Erling Smørgrav             return dname;
656*3fc9e2c3SDag-Erling Smørgrav     }
657*3fc9e2c3SDag-Erling Smørgrav 
658*3fc9e2c3SDag-Erling Smørgrav     searchlist = ldns_resolver_searchlist(res);
659*3fc9e2c3SDag-Erling Smørgrav     n = ldns_resolver_searchlist_count(res);
660*3fc9e2c3SDag-Erling Smørgrav     for (i = 0; i < n; i++) {
661*3fc9e2c3SDag-Erling Smørgrav         dname = safe_dname_cat_clone(domain, searchlist[i]);
662*3fc9e2c3SDag-Erling Smørgrav         if (query(res, dname, pkt))
663*3fc9e2c3SDag-Erling Smørgrav             return dname;
664*3fc9e2c3SDag-Erling Smørgrav     }
665*3fc9e2c3SDag-Erling Smørgrav 
666*3fc9e2c3SDag-Erling Smørgrav     if (!absolute && query(res, domain, pkt))
667*3fc9e2c3SDag-Erling Smørgrav         return domain;
668*3fc9e2c3SDag-Erling Smørgrav 
669*3fc9e2c3SDag-Erling Smørgrav     return NULL;
670*3fc9e2c3SDag-Erling Smørgrav }
671*3fc9e2c3SDag-Erling Smørgrav 
672*3fc9e2c3SDag-Erling Smørgrav static void
673*3fc9e2c3SDag-Erling Smørgrav report(ldns_resolver *res, ldns_rdf *domain, ldns_pkt *pkt) {
674*3fc9e2c3SDag-Erling Smørgrav     ldns_pkt_rcode rcode;
675*3fc9e2c3SDag-Erling Smørgrav 
676*3fc9e2c3SDag-Erling Smørgrav     if (o_print_pkt_server) {
677*3fc9e2c3SDag-Erling Smørgrav         printf("Using domain server:\nName: %s\nAddress: ", o_server);
678*3fc9e2c3SDag-Erling Smørgrav         print_rdf(ldns_pkt_answerfrom(pkt));
679*3fc9e2c3SDag-Erling Smørgrav         printf("#%d\nAliases: \n\n", ldns_resolver_port(res));
680*3fc9e2c3SDag-Erling Smørgrav         o_print_pkt_server = false;
681*3fc9e2c3SDag-Erling Smørgrav     }
682*3fc9e2c3SDag-Erling Smørgrav     rcode = ldns_pkt_get_rcode(pkt);
683*3fc9e2c3SDag-Erling Smørgrav     if (rcode != LDNS_RCODE_NOERROR) {
684*3fc9e2c3SDag-Erling Smørgrav         printf("Host ");
685*3fc9e2c3SDag-Erling Smørgrav         print_rdf_nodot(domain);
686*3fc9e2c3SDag-Erling Smørgrav         printf(" not found: %d(", rcode);
687*3fc9e2c3SDag-Erling Smørgrav         print_rcode(rcode);
688*3fc9e2c3SDag-Erling Smørgrav         printf(")\n");
689*3fc9e2c3SDag-Erling Smørgrav     } else {
690*3fc9e2c3SDag-Erling Smørgrav         if (o_verbose) {
691*3fc9e2c3SDag-Erling Smørgrav             print_pkt_verbose(pkt);
692*3fc9e2c3SDag-Erling Smørgrav         } else {
693*3fc9e2c3SDag-Erling Smørgrav             print_pkt_short(pkt, o_print_rr_server);
694*3fc9e2c3SDag-Erling Smørgrav             if (o_mode != M_DEFAULT_Q &&
695*3fc9e2c3SDag-Erling Smørgrav                 ldns_rr_list_rr_count(ldns_pkt_answer(pkt)) == 0) {
696*3fc9e2c3SDag-Erling Smørgrav                 print_rdf_nodot(domain);
697*3fc9e2c3SDag-Erling Smørgrav                 printf(" has no ");
698*3fc9e2c3SDag-Erling Smørgrav                 print_rr_type(o_rrtype);
699*3fc9e2c3SDag-Erling Smørgrav                 printf(" record\n");
700*3fc9e2c3SDag-Erling Smørgrav             }
701*3fc9e2c3SDag-Erling Smørgrav         }
702*3fc9e2c3SDag-Erling Smørgrav     }
703*3fc9e2c3SDag-Erling Smørgrav     if (o_verbose)
704*3fc9e2c3SDag-Erling Smørgrav         print_received_line(res, pkt);
705*3fc9e2c3SDag-Erling Smørgrav }
706*3fc9e2c3SDag-Erling Smørgrav 
707*3fc9e2c3SDag-Erling Smørgrav static bool
708*3fc9e2c3SDag-Erling Smørgrav doquery(ldns_resolver *res, ldns_rdf *domain) {
709*3fc9e2c3SDag-Erling Smørgrav     ldns_pkt *pkt;
710*3fc9e2c3SDag-Erling Smørgrav     bool q;
711*3fc9e2c3SDag-Erling Smørgrav 
712*3fc9e2c3SDag-Erling Smørgrav     q = query(res, domain, &pkt);
713*3fc9e2c3SDag-Erling Smørgrav     report(res, domain, pkt);
714*3fc9e2c3SDag-Erling Smørgrav     return q;
715*3fc9e2c3SDag-Erling Smørgrav }
716*3fc9e2c3SDag-Erling Smørgrav 
717*3fc9e2c3SDag-Erling Smørgrav static bool
718*3fc9e2c3SDag-Erling Smørgrav doquery_filtered(ldns_resolver *res, ldns_rdf *domain) {
719*3fc9e2c3SDag-Erling Smørgrav     ldns_pkt *pkt;
720*3fc9e2c3SDag-Erling Smørgrav     bool q;
721*3fc9e2c3SDag-Erling Smørgrav 
722*3fc9e2c3SDag-Erling Smørgrav     q = query(res, domain, &pkt);
723*3fc9e2c3SDag-Erling Smørgrav     ldns_pkt_filter_answer(pkt, o_rrtype);
724*3fc9e2c3SDag-Erling Smørgrav     report(res, domain, pkt);
725*3fc9e2c3SDag-Erling Smørgrav     return q;
726*3fc9e2c3SDag-Erling Smørgrav }
727*3fc9e2c3SDag-Erling Smørgrav 
728*3fc9e2c3SDag-Erling Smørgrav static bool
729*3fc9e2c3SDag-Erling Smørgrav dosearch(ldns_resolver *res, ldns_rdf *domain, bool absolute) {
730*3fc9e2c3SDag-Erling Smørgrav     ldns_pkt *pkt;
731*3fc9e2c3SDag-Erling Smørgrav     ldns_rdf *dname;
732*3fc9e2c3SDag-Erling Smørgrav 
733*3fc9e2c3SDag-Erling Smørgrav     dname = search(res, domain, &pkt, absolute);
734*3fc9e2c3SDag-Erling Smørgrav     report(res, dname != NULL ? dname : domain, pkt);
735*3fc9e2c3SDag-Erling Smørgrav     return o_mode != M_DEFAULT_Q ? (dname != NULL) :
736*3fc9e2c3SDag-Erling Smørgrav         (dname != NULL) &&
737*3fc9e2c3SDag-Erling Smørgrav         (o_rrtype = LDNS_RR_TYPE_AAAA, doquery_filtered(res, dname)) &&
738*3fc9e2c3SDag-Erling Smørgrav         (o_rrtype = LDNS_RR_TYPE_MX, doquery_filtered(res, dname));
739*3fc9e2c3SDag-Erling Smørgrav }
740*3fc9e2c3SDag-Erling Smørgrav 
741*3fc9e2c3SDag-Erling Smørgrav static bool
742*3fc9e2c3SDag-Erling Smørgrav doaxfr(ldns_resolver *res, ldns_rdf *domain, bool absolute) {
743*3fc9e2c3SDag-Erling Smørgrav     ldns_pkt *pkt;
744*3fc9e2c3SDag-Erling Smørgrav     ldns_rdf *dname;
745*3fc9e2c3SDag-Erling Smørgrav     ldns_rr_type rrtype;
746*3fc9e2c3SDag-Erling Smørgrav 
747*3fc9e2c3SDag-Erling Smørgrav     rrtype = o_rrtype;
748*3fc9e2c3SDag-Erling Smørgrav     o_rrtype = LDNS_RR_TYPE_AXFR;
749*3fc9e2c3SDag-Erling Smørgrav     dname = search(res, domain, &pkt, absolute);
750*3fc9e2c3SDag-Erling Smørgrav     ldns_pkt_filter_answer(pkt, rrtype);
751*3fc9e2c3SDag-Erling Smørgrav     report(res, dname != NULL ? dname : domain, pkt);
752*3fc9e2c3SDag-Erling Smørgrav     return dname != NULL;
753*3fc9e2c3SDag-Erling Smørgrav }
754*3fc9e2c3SDag-Erling Smørgrav 
755*3fc9e2c3SDag-Erling Smørgrav static bool
756*3fc9e2c3SDag-Erling Smørgrav dosoa(ldns_resolver *res, ldns_rdf *domain, bool absolute) {
757*3fc9e2c3SDag-Erling Smørgrav     ldns_rr_list *answer, **nsaddrs;
758*3fc9e2c3SDag-Erling Smørgrav     ldns_rdf *dname, *addr;
759*3fc9e2c3SDag-Erling Smørgrav     ldns_pkt *pkt;
760*3fc9e2c3SDag-Erling Smørgrav     ldns_rr *rr;
761*3fc9e2c3SDag-Erling Smørgrav     size_t i, j, n, cnt;
762*3fc9e2c3SDag-Erling Smørgrav 
763*3fc9e2c3SDag-Erling Smørgrav     if ((dname = search(res, domain, &pkt, absolute)) == NULL)
764*3fc9e2c3SDag-Erling Smørgrav         return false;
765*3fc9e2c3SDag-Erling Smørgrav 
766*3fc9e2c3SDag-Erling Smørgrav     answer = ldns_pkt_answer(pkt);
767*3fc9e2c3SDag-Erling Smørgrav     cnt = ldns_rr_list_rr_count(answer);
768*3fc9e2c3SDag-Erling Smørgrav     nsaddrs = alloca(cnt*sizeof(*nsaddrs));
769*3fc9e2c3SDag-Erling Smørgrav     for (n = 0, i = 0; i < cnt; i++)
770*3fc9e2c3SDag-Erling Smørgrav         if ((addr = ldns_rr_ns_nsdname(ldns_rr_list_rr(answer, i))) != NULL)
771*3fc9e2c3SDag-Erling Smørgrav             nsaddrs[n++] = ldns_get_rr_list_addr_by_name(res,
772*3fc9e2c3SDag-Erling Smørgrav                 addr, LDNS_RR_CLASS_IN, 0);
773*3fc9e2c3SDag-Erling Smørgrav 
774*3fc9e2c3SDag-Erling Smørgrav     o_print_pkt_server = false;
775*3fc9e2c3SDag-Erling Smørgrav     o_recursive = false;
776*3fc9e2c3SDag-Erling Smørgrav     o_rrtype = LDNS_RR_TYPE_SOA;
777*3fc9e2c3SDag-Erling Smørgrav     for (i = 0; i < n; i++) {
778*3fc9e2c3SDag-Erling Smørgrav         cnt = ldns_rr_list_rr_count(nsaddrs[i]);
779*3fc9e2c3SDag-Erling Smørgrav         for (j = 0; j < cnt; j++) {
780*3fc9e2c3SDag-Erling Smørgrav             ldns_resolver_remove_nameservers(res);
781*3fc9e2c3SDag-Erling Smørgrav             rr = ldns_rr_list_rr(nsaddrs[i], j);
782*3fc9e2c3SDag-Erling Smørgrav             if ((ldns_resolver_ip6(res) == LDNS_RESOLV_INET &&
783*3fc9e2c3SDag-Erling Smørgrav 		    ldns_rr_get_type(rr) == LDNS_RR_TYPE_AAAA) ||
784*3fc9e2c3SDag-Erling Smørgrav                 (ldns_resolver_ip6(res) == LDNS_RESOLV_INET6 &&
785*3fc9e2c3SDag-Erling Smørgrav 		    ldns_rr_get_type(rr) == LDNS_RR_TYPE_A))
786*3fc9e2c3SDag-Erling Smørgrav                 continue;
787*3fc9e2c3SDag-Erling Smørgrav             if (ldns_resolver_push_nameserver_rr(res, rr) == LDNS_STATUS_OK)
788*3fc9e2c3SDag-Erling Smørgrav                 /* bind9-host queries for domain, not dname here */
789*3fc9e2c3SDag-Erling Smørgrav                 doquery(res, dname);
790*3fc9e2c3SDag-Erling Smørgrav         }
791*3fc9e2c3SDag-Erling Smørgrav     }
792*3fc9e2c3SDag-Erling Smørgrav     return 0;
793*3fc9e2c3SDag-Erling Smørgrav }
794*3fc9e2c3SDag-Erling Smørgrav 
795*3fc9e2c3SDag-Erling Smørgrav static void
796*3fc9e2c3SDag-Erling Smørgrav resolver_set_nameserver_hostname(ldns_resolver *res, const char *server) {
797*3fc9e2c3SDag-Erling Smørgrav     struct addrinfo hints, *ailist, *ai;
798*3fc9e2c3SDag-Erling Smørgrav     ldns_status status;
799*3fc9e2c3SDag-Erling Smørgrav     ldns_rdf *rdf;
800*3fc9e2c3SDag-Erling Smørgrav     int err;
801*3fc9e2c3SDag-Erling Smørgrav 
802*3fc9e2c3SDag-Erling Smørgrav     memset(&hints, 0, sizeof hints);
803*3fc9e2c3SDag-Erling Smørgrav     switch (ldns_resolver_ip6(res)) {
804*3fc9e2c3SDag-Erling Smørgrav     case LDNS_RESOLV_INET: hints.ai_family = PF_INET; break;
805*3fc9e2c3SDag-Erling Smørgrav     case LDNS_RESOLV_INET6: hints.ai_family = PF_INET6; break;
806*3fc9e2c3SDag-Erling Smørgrav     default: hints.ai_family = PF_UNSPEC; break;
807*3fc9e2c3SDag-Erling Smørgrav     }
808*3fc9e2c3SDag-Erling Smørgrav     hints.ai_socktype = SOCK_STREAM;
809*3fc9e2c3SDag-Erling Smørgrav     do err = getaddrinfo(server, NULL, &hints, &ailist);
810*3fc9e2c3SDag-Erling Smørgrav     while (err == EAI_AGAIN);
811*3fc9e2c3SDag-Erling Smørgrav     if (err != 0)
812*3fc9e2c3SDag-Erling Smørgrav         die(1, "couldn't get address for '%s': %s", server, gai_strerror(err));
813*3fc9e2c3SDag-Erling Smørgrav     for (ai = ailist; ai != NULL; ai = ai->ai_next) {
814*3fc9e2c3SDag-Erling Smørgrav         if ((rdf = ldns_sockaddr_storage2rdf((void*)ai->ai_addr, NULL)) == NULL)
815*3fc9e2c3SDag-Erling Smørgrav             die(1, "couldn't allocate an rdf: %s",
816*3fc9e2c3SDag-Erling Smørgrav                 ldns_get_errorstr_by_id(LDNS_STATUS_MEM_ERR));
817*3fc9e2c3SDag-Erling Smørgrav         status = ldns_resolver_push_nameserver(res, rdf);
818*3fc9e2c3SDag-Erling Smørgrav         if (status != LDNS_STATUS_OK)
819*3fc9e2c3SDag-Erling Smørgrav             die(1, "couldn't push a nameserver address: %s",
820*3fc9e2c3SDag-Erling Smørgrav                 ldns_get_errorstr_by_id(status));
821*3fc9e2c3SDag-Erling Smørgrav     }
822*3fc9e2c3SDag-Erling Smørgrav }
823*3fc9e2c3SDag-Erling Smørgrav 
824*3fc9e2c3SDag-Erling Smørgrav static void
825*3fc9e2c3SDag-Erling Smørgrav resolver_set_nameserver_str(ldns_resolver *res, const char *server) {
826*3fc9e2c3SDag-Erling Smørgrav     ldns_rdf *addr;
827*3fc9e2c3SDag-Erling Smørgrav 
828*3fc9e2c3SDag-Erling Smørgrav     ldns_resolver_remove_nameservers(res);
829*3fc9e2c3SDag-Erling Smørgrav     addr = ldns_rdf_new_addr_frm_str(server);
830*3fc9e2c3SDag-Erling Smørgrav     if (addr) {
831*3fc9e2c3SDag-Erling Smørgrav         if (ldns_resolver_push_nameserver(res, addr) != LDNS_STATUS_OK)
832*3fc9e2c3SDag-Erling Smørgrav             die(1, "couldn't push a nameserver address");
833*3fc9e2c3SDag-Erling Smørgrav     } else
834*3fc9e2c3SDag-Erling Smørgrav         resolver_set_nameserver_hostname(res, server);
835*3fc9e2c3SDag-Erling Smørgrav }
836*3fc9e2c3SDag-Erling Smørgrav 
837*3fc9e2c3SDag-Erling Smørgrav int
838*3fc9e2c3SDag-Erling Smørgrav main(int argc, char *argv[]) {
839*3fc9e2c3SDag-Erling Smørgrav     ldns_rdf *addr, *dname;
840*3fc9e2c3SDag-Erling Smørgrav     ldns_resolver *res;
841*3fc9e2c3SDag-Erling Smørgrav     ldns_status status;
842*3fc9e2c3SDag-Erling Smørgrav     struct timeval restimeout;
843*3fc9e2c3SDag-Erling Smørgrav 
844*3fc9e2c3SDag-Erling Smørgrav     parse_args(argc, argv);
845*3fc9e2c3SDag-Erling Smørgrav 
846*3fc9e2c3SDag-Erling Smørgrav     status = ldns_resolver_new_default(&res);
847*3fc9e2c3SDag-Erling Smørgrav     if (status != LDNS_STATUS_OK)
848*3fc9e2c3SDag-Erling Smørgrav         die(1, "error creating resolver: %s", ldns_get_errorstr_by_id(status));
849*3fc9e2c3SDag-Erling Smørgrav     if (ldns_resolver_nameserver_count(res) == 0)
850*3fc9e2c3SDag-Erling Smørgrav         ldns_resolver_push_default_servers(res);
851*3fc9e2c3SDag-Erling Smørgrav 
852*3fc9e2c3SDag-Erling Smørgrav     ldns_resolver_set_usevc(res, o_tcp);
853*3fc9e2c3SDag-Erling Smørgrav     restimeout.tv_sec = o_timeout > 0 ? o_timeout :
854*3fc9e2c3SDag-Erling Smørgrav         o_tcp ? DEFAULT_TCP_TIMEOUT : DEFAULT_UDP_TIMEOUT;
855*3fc9e2c3SDag-Erling Smørgrav     restimeout.tv_usec = 0;
856*3fc9e2c3SDag-Erling Smørgrav     ldns_resolver_set_timeout(res, restimeout);
857*3fc9e2c3SDag-Erling Smørgrav     ldns_resolver_set_retry(res, o_retries+1);
858*3fc9e2c3SDag-Erling Smørgrav     ldns_resolver_set_ip6(res, o_ipversion);
859*3fc9e2c3SDag-Erling Smørgrav     ldns_resolver_set_defnames(res, false);
860*3fc9e2c3SDag-Erling Smørgrav     ldns_resolver_set_fallback(res, false);
861*3fc9e2c3SDag-Erling Smørgrav 
862*3fc9e2c3SDag-Erling Smørgrav     if (o_server)
863*3fc9e2c3SDag-Erling Smørgrav         resolver_set_nameserver_str(res, o_server);
864*3fc9e2c3SDag-Erling Smørgrav 
865*3fc9e2c3SDag-Erling Smørgrav     if (ldns_str2rdf_a(&addr, o_name) == LDNS_STATUS_OK) {
866*3fc9e2c3SDag-Erling Smørgrav         dname = ldns_rdf_reverse_a(addr, "in-addr.arpa");
867*3fc9e2c3SDag-Erling Smørgrav         if (dname == NULL)
868*3fc9e2c3SDag-Erling Smørgrav             die(1, "can't reverse '%s': %s", o_name,
869*3fc9e2c3SDag-Erling Smørgrav                 ldns_get_errorstr_by_id(LDNS_STATUS_MEM_ERR));
870*3fc9e2c3SDag-Erling Smørgrav         o_mode = M_SINGLE_Q;
871*3fc9e2c3SDag-Erling Smørgrav         o_rrtype = LDNS_RR_TYPE_PTR;
872*3fc9e2c3SDag-Erling Smørgrav         return !doquery(res, dname);
873*3fc9e2c3SDag-Erling Smørgrav     } else if (ldns_str2rdf_aaaa(&addr, o_name) == LDNS_STATUS_OK) {
874*3fc9e2c3SDag-Erling Smørgrav         dname = ldns_rdf_reverse_aaaa(addr, o_ip6_int ? "ip6.int" : "ip6.arpa");
875*3fc9e2c3SDag-Erling Smørgrav         if (dname == NULL)
876*3fc9e2c3SDag-Erling Smørgrav             die(1, "can't reverse '%s': %s", o_name,
877*3fc9e2c3SDag-Erling Smørgrav                 ldns_get_errorstr_by_id(LDNS_STATUS_MEM_ERR));
878*3fc9e2c3SDag-Erling Smørgrav         o_mode = M_SINGLE_Q;
879*3fc9e2c3SDag-Erling Smørgrav         o_rrtype = LDNS_RR_TYPE_PTR;
880*3fc9e2c3SDag-Erling Smørgrav         return !doquery(res, dname);
881*3fc9e2c3SDag-Erling Smørgrav     }
882*3fc9e2c3SDag-Erling Smørgrav     return !(o_mode == M_SOA ? dosoa : o_mode == M_AXFR ? doaxfr : dosearch)
883*3fc9e2c3SDag-Erling Smørgrav         (res, safe_str2rdf_dname(o_name), ndots(o_name) >= o_ndots);
884*3fc9e2c3SDag-Erling Smørgrav }
885