1254939Sdes/*- 2254939Sdes * (c) Magerya Vitaly 3254939Sdes * 4254939Sdes * Copying and distribution of this file, with or without modification, 5254939Sdes * are permitted in any medium without royalty provided the copyright 6254939Sdes * notice and this notice are preserved. This file is offered as-is, 7254939Sdes * without any warranty. 8254939Sdes */ 9254939Sdes 10301759Sdes#include <ldns/ldns.h> 11254939Sdes#include <limits.h> 12254939Sdes#include <netdb.h> 13301759Sdes#include <netinet/in.h> 14254939Sdes#include <stdio.h> 15254939Sdes#include <stdlib.h> 16254939Sdes#include <unistd.h> 17254939Sdes 18254939Sdes/* General utilities. 19254939Sdes */ 20254939Sdes 21254939Sdesstatic char *progname; 22254939Sdes 23254939Sdes#define countof(array) (sizeof(array)/sizeof(*(array))) 24254939Sdes 25254939Sdesstatic void 26254939Sdesdie(int code, const char *fmt, ...) { 27254939Sdes va_list args; 28254939Sdes 29254939Sdes va_start(args, fmt); 30254939Sdes fprintf(stderr, "%s: ", progname); 31254939Sdes vfprintf(stderr, fmt, args); 32254939Sdes fprintf(stderr, "\n"); 33254939Sdes va_end(args); 34254939Sdes exit(code); 35254939Sdes} 36254939Sdes 37254939Sdesstatic int 38254939Sdesndots(const char *name) { 39254939Sdes int n; 40254939Sdes 41254939Sdes for (n = 0; (name = strchr(name, '.')); n++, name++); 42254939Sdes return n; 43254939Sdes} 44254939Sdes 45254939Sdes/* General LDNS-specific utilities. 46254939Sdes */ 47254939Sdes 48254939Sdesstatic ldns_status 49254939Sdesldns_resolver_new_default(ldns_resolver **res) { 50254939Sdes if (ldns_resolver_new_frm_file(res, NULL) == LDNS_STATUS_OK || 51254939Sdes (*res = ldns_resolver_new()) != NULL) 52254939Sdes return LDNS_STATUS_OK; 53254939Sdes return LDNS_STATUS_MEM_ERR; 54254939Sdes} 55254939Sdes 56254939Sdesstatic ldns_status 57254939Sdesldns_resolver_push_default_servers(ldns_resolver *res) { 58254939Sdes ldns_status status; 59254939Sdes ldns_rdf *addr; 60254939Sdes 61254939Sdes if ((status = ldns_str2rdf_a(&addr, "127.0.0.1")) != LDNS_STATUS_OK || 62254939Sdes (status = ldns_resolver_push_nameserver(res, addr)) != LDNS_STATUS_OK) 63254939Sdes return ldns_rdf_deep_free(addr), status; 64254939Sdes ldns_rdf_deep_free(addr); 65254939Sdes if ((status = ldns_str2rdf_aaaa(&addr, "::1")) != LDNS_STATUS_OK || 66254939Sdes (status = ldns_resolver_push_nameserver(res, addr)) != LDNS_STATUS_OK) 67254939Sdes return ldns_rdf_deep_free(addr), status; 68254939Sdes ldns_rdf_deep_free(addr); 69254939Sdes return LDNS_STATUS_OK; 70254939Sdes} 71254939Sdes 72254939Sdesstatic ldns_rdf * 73254939Sdesldns_rdf_new_addr_frm_str(const char *str) { 74254939Sdes ldns_rdf *addr; 75254939Sdes 76254939Sdes if ((addr = ldns_rdf_new_frm_str(LDNS_RDF_TYPE_A, str)) == NULL) 77254939Sdes addr = ldns_rdf_new_frm_str(LDNS_RDF_TYPE_AAAA, str); 78254939Sdes return addr; 79254939Sdes} 80254939Sdes 81254939Sdesstatic void 82254939Sdesldns_resolver_remove_nameservers(ldns_resolver *res) { 83254939Sdes while (ldns_resolver_nameserver_count(res) > 0) 84254939Sdes ldns_rdf_deep_free(ldns_resolver_pop_nameserver(res)); 85254939Sdes} 86254939Sdes 87254939Sdesstatic ldns_rdf * 88254939Sdesldns_rdf_reverse_a(ldns_rdf *addr, const char *base) { 89254939Sdes char *buf; 90254939Sdes int i, len; 91254939Sdes 92254939Sdes len = strlen(base); 93254939Sdes buf = alloca(LDNS_IP4ADDRLEN*4 + len + 1); 94254939Sdes for (len = i = 0; i < LDNS_IP4ADDRLEN; i++) 95254939Sdes len += sprintf(&buf[len], "%d.", 96254939Sdes (int)ldns_rdf_data(addr)[LDNS_IP4ADDRLEN - i - 1]); 97254939Sdes sprintf(&buf[len], "%s", base); 98254939Sdes return ldns_dname_new_frm_str(buf); 99254939Sdes} 100254939Sdes 101254939Sdesstatic ldns_rdf * 102254939Sdesldns_rdf_reverse_aaaa(ldns_rdf *addr, const char *base) { 103254939Sdes char *buf; 104254939Sdes int i, len; 105254939Sdes 106254939Sdes len = strlen(base); 107254939Sdes buf = alloca(LDNS_IP6ADDRLEN*4 + len + 1); 108254939Sdes for (i = 0; i < LDNS_IP6ADDRLEN; i++) { 109254939Sdes uint8_t byte = ldns_rdf_data(addr)[LDNS_IP6ADDRLEN - i - 1]; 110254939Sdes sprintf(&buf[i*4], "%x.%x.", byte & 0x0F, byte >> 4); 111254939Sdes } 112254939Sdes sprintf(&buf[LDNS_IP6ADDRLEN*4], "%s", base); 113254939Sdes return ldns_dname_new_frm_str(buf); 114254939Sdes} 115254939Sdes 116254939Sdesstatic ldns_status 117254939Sdesldns_pkt_push_rr_soa(ldns_pkt *pkt, ldns_pkt_section sec, 118254939Sdes const ldns_rdf *name, ldns_rr_class c, uint32_t serial) { 119254939Sdes ldns_rdf *rdf; 120254939Sdes ldns_rr *rr; 121254939Sdes uint32_t n; 122254939Sdes 123254939Sdes if ((rr = ldns_rr_new_frm_type(LDNS_RR_TYPE_SOA)) == NULL) 124254939Sdes return LDNS_STATUS_MEM_ERR; 125254939Sdes ldns_rr_set_class(rr, c); 126254939Sdes ldns_rr_set_owner(rr, ldns_rdf_clone(name)); 127254939Sdes ldns_rr_set_ttl(rr, 0); 128254939Sdes 129254939Sdes n = 0; 130254939Sdes if ((rdf = ldns_rdf_new_frm_data(LDNS_RDF_TYPE_DNAME, 1, &n)) == NULL) 131254939Sdes goto memerr; 132254939Sdes ldns_rr_set_rdf(rr, rdf, 0); 133254939Sdes ldns_rr_set_rdf(rr, ldns_rdf_clone(rdf), 1); 134254939Sdes 135254939Sdes n = htonl(serial); 136254939Sdes if ((rdf = ldns_rdf_new_frm_data(LDNS_RDF_TYPE_INT32, 4, &n)) == NULL) 137254939Sdes goto memerr; 138254939Sdes ldns_rr_set_rdf(rr, rdf, 2); 139254939Sdes 140254939Sdes n = 0; 141254939Sdes if ((rdf = ldns_rdf_new_frm_data(LDNS_RDF_TYPE_PERIOD, 4, &n)) == NULL) 142254939Sdes goto memerr; 143254939Sdes ldns_rr_set_rdf(rr, rdf, 3); 144254939Sdes ldns_rr_set_rdf(rr, ldns_rdf_clone(rdf), 4); 145254939Sdes ldns_rr_set_rdf(rr, ldns_rdf_clone(rdf), 5); 146254939Sdes ldns_rr_set_rdf(rr, ldns_rdf_clone(rdf), 6); 147254939Sdes 148254939Sdes if (ldns_rr_rdf(rr, 1) == NULL || ldns_rr_rdf(rr, 4) == NULL || 149254939Sdes ldns_rr_rdf(rr, 5) == NULL || ldns_rr_rdf(rr, 6) == NULL || 150254939Sdes !ldns_pkt_push_rr(pkt, sec, rr)) 151254939Sdes goto memerr; 152254939Sdes return LDNS_STATUS_OK; 153254939Sdes 154254939Sdesmemerr: 155254939Sdes ldns_rr_free(rr); 156254939Sdes return LDNS_STATUS_MEM_ERR; 157254939Sdes} 158254939Sdes 159254939Sdesstatic ldns_status 160301759Sdesldns_tcp_start(ldns_resolver *res, ldns_pkt *qpkt, int nameserver) { 161301759Sdes /* This routine is based on ldns_axfr_start, with the major 162301759Sdes * difference in that it takes a query packet explicitly. 163301759Sdes */ 164301759Sdes struct sockaddr_storage *ns = NULL; 165301759Sdes size_t ns_len = 0; 166301759Sdes ldns_buffer *qbuf = NULL; 167301759Sdes ldns_status status; 168301759Sdes 169301759Sdes ns = ldns_rdf2native_sockaddr_storage( 170301759Sdes res->_nameservers[nameserver], ldns_resolver_port(res), &ns_len); 171301759Sdes if (ns == NULL) { 172301759Sdes status = LDNS_STATUS_MEM_ERR; 173301759Sdes goto error; 174301759Sdes } 175301759Sdes 176301759Sdes res->_socket = ldns_tcp_connect( 177301759Sdes ns, (socklen_t)ns_len, ldns_resolver_timeout(res)); 178301759Sdes if (res->_socket <= 0) { 179301759Sdes status = LDNS_STATUS_ADDRESS_ERR; 180301759Sdes goto error; 181301759Sdes } 182301759Sdes 183301759Sdes qbuf = ldns_buffer_new(LDNS_MAX_PACKETLEN); 184301759Sdes if (qbuf == NULL) { 185301759Sdes status = LDNS_STATUS_MEM_ERR; 186301759Sdes goto error; 187301759Sdes } 188301759Sdes 189301759Sdes status = ldns_pkt2buffer_wire(qbuf, qpkt); 190301759Sdes if (status != LDNS_STATUS_OK) 191301759Sdes goto error; 192301759Sdes 193301759Sdes if (ldns_tcp_send_query(qbuf, res->_socket, ns, (socklen_t)ns_len) == 0) { 194301759Sdes status = LDNS_STATUS_NETWORK_ERR; 195301759Sdes goto error; 196301759Sdes } 197301759Sdes 198301759Sdes ldns_buffer_free(qbuf); 199301759Sdes free(ns); 200301759Sdes return LDNS_STATUS_OK; 201301759Sdes 202301759Sdeserror: 203301759Sdes ldns_buffer_free(qbuf); 204301759Sdes free(ns); 205301759Sdes if (res->_socket > 0) { 206301759Sdes close(res->_socket); 207301759Sdes res->_socket = 0; 208301759Sdes } 209301759Sdes return status; 210301759Sdes} 211301759Sdes 212301759Sdesstatic ldns_status 213301759Sdesldns_tcp_read(ldns_pkt **answer, ldns_resolver *res) { 214301759Sdes ldns_status status; 215301759Sdes struct timeval t1, t2; 216301759Sdes uint8_t *data; 217301759Sdes size_t size; 218301759Sdes 219301759Sdes if (res->_socket <= 0) 220301759Sdes return LDNS_STATUS_ERR; 221301759Sdes 222301759Sdes gettimeofday(&t1, NULL); 223301759Sdes data = ldns_tcp_read_wire_timeout( 224301759Sdes res->_socket, &size, ldns_resolver_timeout(res)); 225301759Sdes if (data == NULL) 226301759Sdes goto error; 227301759Sdes 228301759Sdes status = ldns_wire2pkt(answer, data, size); 229301759Sdes free(data); 230301759Sdes if (status != LDNS_STATUS_OK) 231301759Sdes goto error; 232301759Sdes 233301759Sdes gettimeofday(&t2, NULL); 234301759Sdes ldns_pkt_set_querytime(*answer, 235301759Sdes (uint32_t)((t2.tv_sec - t1.tv_sec)*1000) + 236301759Sdes (t2.tv_usec - t1.tv_usec)/1000); 237301759Sdes ldns_pkt_set_timestamp(*answer, t2); 238301759Sdes return status; 239301759Sdes 240301759Sdeserror: 241301759Sdes close(res->_socket); 242301759Sdes res->_socket = 0; 243301759Sdes return LDNS_STATUS_ERR; 244301759Sdes} 245301759Sdes 246301759Sdesstatic void 247301759Sdesldns_tcp_close(ldns_resolver *res) { 248301759Sdes if (res->_socket > 0) { 249301759Sdes close(res->_socket); 250301759Sdes res->_socket = 0; 251301759Sdes } 252301759Sdes} 253301759Sdes 254301759Sdesstatic ldns_status 255254939Sdesldns_resolver_send_to(ldns_pkt **answer, ldns_resolver *res, 256254939Sdes const ldns_rdf *name, ldns_rr_type t, ldns_rr_class c, 257301759Sdes uint16_t flags, uint32_t ixfr_serial, int nameserver, 258301759Sdes bool close_tcp) { 259301759Sdes ldns_status status = LDNS_STATUS_OK; 260254939Sdes ldns_pkt *qpkt; 261301759Sdes struct timeval now; 262254939Sdes 263254939Sdes int nscnt = ldns_resolver_nameserver_count(res); 264254939Sdes ldns_rdf **ns = ldns_resolver_nameservers(res); 265254939Sdes size_t *rtt = ldns_resolver_rtt(res); 266254939Sdes 267254939Sdes ldns_resolver_set_nameservers(res, &ns[nameserver]); 268254939Sdes ldns_resolver_set_rtt(res, &rtt[nameserver]); 269254939Sdes ldns_resolver_set_nameserver_count(res, 1); 270254939Sdes 271301759Sdes /* The next fragment should have been a call to 272301759Sdes * ldns_resolver_prepare_query_pkt(), but starting with ldns 273301759Sdes * version 1.6.17 that function tries to add it's own SOA 274301759Sdes * records when rr_type is LDNS_RR_TYPE_IXFR, and we don't 275301759Sdes * want that. 276301759Sdes */ 277301759Sdes qpkt = ldns_pkt_query_new(ldns_rdf_clone(name), t, c, flags); 278301759Sdes if (qpkt == NULL) { 279301759Sdes status = LDNS_STATUS_ERR; 280301759Sdes goto done; 281301759Sdes } 282301759Sdes now.tv_sec = time(NULL); 283301759Sdes now.tv_usec = 0; 284301759Sdes ldns_pkt_set_timestamp(qpkt, now); 285301759Sdes ldns_pkt_set_random_id(qpkt); 286301759Sdes 287301759Sdes if (t == LDNS_RR_TYPE_IXFR) { 288254939Sdes status = ldns_pkt_push_rr_soa(qpkt, 289254939Sdes LDNS_SECTION_AUTHORITY, name, c, ixfr_serial); 290301759Sdes if (status != LDNS_STATUS_OK) goto done; 291301759Sdes } 292301759Sdes if (close_tcp) { 293254939Sdes status = ldns_resolver_send_pkt(answer, res, qpkt); 294301759Sdes } else { 295301759Sdes status = ldns_tcp_start(res, qpkt, 0); 296301759Sdes if (status != LDNS_STATUS_OK) goto done; 297301759Sdes status = ldns_tcp_read(answer, res); 298301759Sdes if (status != LDNS_STATUS_OK) goto done; 299301759Sdes ldns_pkt_set_answerfrom(*answer, ldns_rdf_clone(ns[0])); 300301759Sdes } 301301759Sdes 302301759Sdesdone: 303254939Sdes ldns_pkt_free(qpkt); 304254939Sdes 305254939Sdes ldns_resolver_set_nameservers(res, ns); 306254939Sdes ldns_resolver_set_rtt(res, rtt); 307254939Sdes ldns_resolver_set_nameserver_count(res, nscnt); 308254939Sdes return status; 309254939Sdes} 310254939Sdes 311254939Sdesstatic void 312254939Sdesldns_pkt_filter_answer(ldns_pkt *pkt, ldns_rr_type type) { 313254939Sdes int i, j, cnt; 314254939Sdes ldns_rr_list *rrlist; 315254939Sdes ldns_rr *rr; 316254939Sdes ldns_rr_type rrtype; 317254939Sdes 318254939Sdes rrlist = ldns_pkt_answer(pkt); 319254939Sdes cnt = ldns_rr_list_rr_count(rrlist); 320254939Sdes for (i = j = 0; i < cnt; i++) { 321254939Sdes rr = ldns_rr_list_rr(rrlist, i); 322254939Sdes rrtype = ldns_rr_get_type(rr); 323254939Sdes if (type == LDNS_RR_TYPE_ANY || 324254939Sdes type == rrtype || 325255403Sdes (type == LDNS_RR_TYPE_AXFR && 326254939Sdes (rrtype == LDNS_RR_TYPE_A || 327301759Sdes rrtype == LDNS_RR_TYPE_AAAA || 328301759Sdes rrtype == LDNS_RR_TYPE_NS || 329301759Sdes rrtype == LDNS_RR_TYPE_PTR))) 330254939Sdes ldns_rr_list_set_rr(rrlist, rr, j++); 331254939Sdes } 332254939Sdes ldns_rr_list_set_rr_count(rrlist, j); 333254939Sdes} 334254939Sdes 335254939Sdes/* Packet content printing. 336254939Sdes */ 337254939Sdes 338254939Sdesstatic struct { 339254939Sdes ldns_rr_type type; 340254939Sdes const char *text; 341254939Sdes} rr_types[] = { 342254939Sdes {LDNS_RR_TYPE_A, "has address"}, 343254939Sdes {LDNS_RR_TYPE_NS, "name server"}, 344254939Sdes {LDNS_RR_TYPE_CNAME, "is an alias for"}, 345254939Sdes {LDNS_RR_TYPE_WKS, "has well known services"}, 346254939Sdes {LDNS_RR_TYPE_PTR, "domain name pointer"}, 347254939Sdes {LDNS_RR_TYPE_HINFO, "host information"}, 348254939Sdes {LDNS_RR_TYPE_MX, "mail is handled by"}, 349254939Sdes {LDNS_RR_TYPE_TXT, "descriptive text"}, 350254939Sdes {LDNS_RR_TYPE_X25, "x25 address"}, 351254939Sdes {LDNS_RR_TYPE_ISDN, "ISDN address"}, 352254939Sdes {LDNS_RR_TYPE_SIG, "has signature"}, 353254939Sdes {LDNS_RR_TYPE_KEY, "has key"}, 354254939Sdes {LDNS_RR_TYPE_AAAA, "has IPv6 address"}, 355254939Sdes {LDNS_RR_TYPE_LOC, "location"}, 356254939Sdes}; 357254939Sdes 358254939Sdesstatic void 359254939Sdesprint_opcode(ldns_pkt_opcode opcode) { 360254939Sdes ldns_lookup_table *lt = ldns_lookup_by_id(ldns_opcodes, opcode); 361254939Sdes 362254939Sdes if (lt && lt->name) 363254939Sdes printf("%s", lt->name); 364254939Sdes else 365254939Sdes printf("RESERVED%d", opcode); 366254939Sdes} 367254939Sdes 368254939Sdesstatic void 369254939Sdesprint_rcode(uint8_t rcode) { 370254939Sdes ldns_lookup_table *lt = ldns_lookup_by_id(ldns_rcodes, rcode); 371254939Sdes 372254939Sdes if (lt && lt->name) 373254939Sdes printf("%s", lt->name); 374254939Sdes else 375254939Sdes printf("RESERVED%d", rcode); 376254939Sdes} 377254939Sdes 378254939Sdesstatic int 379254939Sdesprint_rr_type(ldns_rr_type type) { 380254939Sdes char *str; 381254939Sdes int n; 382254939Sdes 383254939Sdes str = ldns_rr_type2str(type); 384254939Sdes n = printf("%s", str); 385254939Sdes free(str); 386254939Sdes return n; 387254939Sdes} 388254939Sdes 389254939Sdesstatic int 390254939Sdesprint_rr_class(ldns_rr_class cls) { 391254939Sdes char *str; 392254939Sdes int n; 393254939Sdes 394254939Sdes str = ldns_rr_class2str(cls); 395254939Sdes n = printf("%s", str); 396254939Sdes free(str); 397254939Sdes return n; 398254939Sdes} 399254939Sdes 400254939Sdesstatic int 401254939Sdesprint_rdf(ldns_rdf *rdf) { 402254939Sdes char *str; 403254939Sdes int n; 404254939Sdes 405254939Sdes str = ldns_rdf2str(rdf); 406254939Sdes n = printf("%s", str); 407254939Sdes free(str); 408254939Sdes return n; 409254939Sdes} 410254939Sdes 411254939Sdesstatic int 412254939Sdesprint_rdf_nodot(ldns_rdf *rdf) { 413254939Sdes char *str; 414254939Sdes int len, n; 415254939Sdes 416254939Sdes str = ldns_rdf2str(rdf); 417254939Sdes len = strlen(str); 418254939Sdes n = printf("%.*s", str[len-1] == '.' ? len-1 : len, str); 419254939Sdes free(str); 420254939Sdes return n; 421254939Sdes} 422254939Sdes 423254939Sdesstatic int 424254939Sdesprint_padding(int fromcol, int tocol) { 425254939Sdes int col = fromcol, nextcol = fromcol + 8 - fromcol%8; 426254939Sdes 427254939Sdes if (fromcol + 1 > tocol) tocol = fromcol + 1; 428254939Sdes for (; nextcol <= tocol; col = nextcol, nextcol += 8) 429254939Sdes printf("\t"); 430254939Sdes for (; col < tocol; col++) 431254939Sdes printf(" "); 432254939Sdes return col - fromcol; 433254939Sdes} 434254939Sdes 435254939Sdesstatic void 436254939Sdesprint_rr_verbose(ldns_rr *rr) { 437254939Sdes bool isq = ldns_rr_is_question(rr); 438254939Sdes int rdcnt = ldns_rr_rd_count(rr); 439254939Sdes int i, n; 440254939Sdes 441254939Sdes /* bind9-host does not count the initial ';' here */ 442254939Sdes n = isq ? printf(";") : 0; 443254939Sdes n = print_rdf(ldns_rr_owner(rr)); 444254939Sdes if (!isq) { 445254939Sdes n += print_padding(n, 24); 446254939Sdes n += printf("%d", ldns_rr_ttl(rr)); 447254939Sdes } 448254939Sdes n += print_padding(n, 32); 449254939Sdes n += print_rr_class(ldns_rr_get_class(rr)); 450254939Sdes n += print_padding(n, 40); 451254939Sdes n += print_rr_type(ldns_rr_get_type(rr)); 452254939Sdes for (i = 0; i < rdcnt; i++) { 453254939Sdes if (i == 0) print_padding(n, 48); 454254939Sdes else printf(" "); 455254939Sdes print_rdf(ldns_rr_rdf(rr, i)); 456254939Sdes } 457254939Sdes printf("\n"); 458254939Sdes} 459254939Sdes 460254939Sdesstatic void 461254939Sdesprint_pkt_section_verbose(const char *name, ldns_rr_list *rrlist) { 462254939Sdes int i, cnt = ldns_rr_list_rr_count(rrlist); 463254939Sdes 464254939Sdes if (cnt == 0) 465254939Sdes return; 466254939Sdes printf(";; %s SECTION:\n", name); 467254939Sdes for (i = 0; i < cnt; i++) 468254939Sdes print_rr_verbose(ldns_rr_list_rr(rrlist, i)); 469254939Sdes printf("\n"); 470254939Sdes} 471254939Sdes 472254939Sdesstatic void 473254939Sdesprint_pkt_verbose(ldns_pkt *pkt) { 474254939Sdes int got_flags = 0; 475254939Sdes 476254939Sdes printf(";; ->>HEADER<<- opcode: "); 477254939Sdes print_opcode(ldns_pkt_get_opcode(pkt)); 478254939Sdes printf(", status: "); 479254939Sdes print_rcode(ldns_pkt_get_rcode(pkt)); 480254939Sdes printf(", id: %u\n", ldns_pkt_id(pkt)); 481254939Sdes printf(";; flags:"); 482254939Sdes if (ldns_pkt_qr(pkt)) printf(" qr"), got_flags = 1; 483254939Sdes if (ldns_pkt_aa(pkt)) printf(" aa"), got_flags = 1; 484254939Sdes if (ldns_pkt_tc(pkt)) printf(" tc"), got_flags = 1; 485254939Sdes if (ldns_pkt_rd(pkt)) printf(" rd"), got_flags = 1; 486254939Sdes if (ldns_pkt_ra(pkt)) printf(" ra"), got_flags = 1; 487254939Sdes if (ldns_pkt_ad(pkt)) printf(" ad"), got_flags = 1; 488254939Sdes if (ldns_pkt_cd(pkt)) printf(" cd"), got_flags = 1; 489254939Sdes if (!got_flags) printf(" "); 490254939Sdes printf("; QUERY: %u, ANSWER: %u, AUTHORITY: %u, ADDITIONAL: %u\n", 491254939Sdes ldns_pkt_qdcount(pkt), ldns_pkt_ancount(pkt), 492254939Sdes ldns_pkt_nscount(pkt), ldns_pkt_arcount(pkt)); 493254939Sdes if (ldns_pkt_edns(pkt)) 494254939Sdes printf(";; EDNS: version: %u, udp=%u\n", 495254939Sdes ldns_pkt_edns_version(pkt), ldns_pkt_edns_udp_size(pkt)); 496254939Sdes printf("\n"); 497254939Sdes print_pkt_section_verbose("QUESTION", ldns_pkt_question(pkt)); 498254939Sdes print_pkt_section_verbose("ANSWER", ldns_pkt_answer(pkt)); 499254939Sdes print_pkt_section_verbose("AUTHORITY", ldns_pkt_authority(pkt)); 500254939Sdes print_pkt_section_verbose("ADDITIONAL", ldns_pkt_additional(pkt)); 501254939Sdes} 502254939Sdes 503254939Sdesstatic void 504254939Sdesprint_rr_short(ldns_rr *rr) { 505254939Sdes ldns_rr_type type = ldns_rr_get_type(rr); 506254939Sdes size_t i, rdcnt = ldns_rr_rd_count(rr); 507254939Sdes 508254939Sdes print_rdf_nodot(ldns_rr_owner(rr)); 509254939Sdes printf(" "); 510254939Sdes for (i = 0; i < countof(rr_types); i++) { 511254939Sdes if (rr_types[i].type == type) { 512254939Sdes printf("%s", rr_types[i].text); 513254939Sdes goto found; 514254939Sdes } 515254939Sdes } 516254939Sdes 517254939Sdes printf("has "); 518254939Sdes print_rr_type(type); 519254939Sdes printf(" record"); 520254939Sdes 521254939Sdesfound: 522254939Sdes for (i = 0; i < rdcnt; i++) { 523254939Sdes printf(" "); 524254939Sdes print_rdf(ldns_rr_rdf(rr, i)); 525254939Sdes } 526254939Sdes printf("\n"); 527254939Sdes} 528254939Sdes 529254939Sdesstatic void 530254939Sdesprint_pkt_short(ldns_pkt *pkt, bool print_rr_server) { 531254939Sdes ldns_rr_list *rrlist = ldns_pkt_answer(pkt); 532254939Sdes size_t i; 533254939Sdes 534254939Sdes for (i = 0; i < ldns_rr_list_rr_count(rrlist); i++) { 535254939Sdes if (print_rr_server) { 536254939Sdes printf("Nameserver "); 537254939Sdes print_rdf(ldns_pkt_answerfrom(pkt)); 538254939Sdes printf(":\n\t"); 539254939Sdes } 540254939Sdes print_rr_short(ldns_rr_list_rr(rrlist, i)); 541254939Sdes } 542254939Sdes} 543254939Sdes 544254939Sdesstatic void 545254939Sdesprint_received_line(ldns_resolver *res, ldns_pkt *pkt) { 546254939Sdes char *from = ldns_rdf2str(ldns_pkt_answerfrom(pkt)); 547254939Sdes 548254939Sdes printf("Received %zu bytes from %s#%d in %d ms\n", 549254939Sdes ldns_pkt_size(pkt), from, ldns_resolver_port(res), 550254939Sdes ldns_pkt_querytime(pkt)); 551254939Sdes free(from); 552254939Sdes} 553254939Sdes 554254939Sdes/* Main program. 555254939Sdes * 556254939Sdes * Note that no memory is freed below this line by intention. 557254939Sdes */ 558254939Sdes 559254939Sdes#define DEFAULT_TCP_TIMEOUT 10 560254939Sdes#define DEFAULT_UDP_TIMEOUT 5 561254939Sdes 562301759Sdesenum operation_mode { M_AXFR, M_IXFR, M_DEFAULT_Q, M_SINGLE_Q, M_SOA }; 563254939Sdes 564254939Sdesstatic enum operation_mode o_mode = M_DEFAULT_Q; 565254939Sdesstatic bool o_ignore_servfail = true; 566254939Sdesstatic bool o_ip6_int = false; 567254939Sdesstatic bool o_print_pkt_server = false; 568254939Sdesstatic bool o_print_rr_server = false; 569254939Sdesstatic bool o_recursive = true; 570254939Sdesstatic bool o_tcp = false; 571254939Sdesstatic bool o_verbose = false; 572254939Sdesstatic char *o_name = NULL; 573254939Sdesstatic char *o_server = NULL; 574254939Sdesstatic int o_ipversion = LDNS_RESOLV_INETANY; 575254939Sdesstatic int o_ndots = 1; 576254939Sdesstatic int o_retries = 1; 577254939Sdesstatic ldns_rr_class o_rrclass = LDNS_RR_CLASS_IN; 578301759Sdesstatic ldns_rr_type o_rrtype = (ldns_rr_type)-1; 579254939Sdesstatic time_t o_timeout = 0; 580254939Sdesstatic uint32_t o_ixfr_serial = 0; 581254939Sdes 582254939Sdesstatic void 583254939Sdesusage(void) { 584301759Sdes fprintf(stderr, 585301759Sdes "Usage: %s [-aCdilrsTvw46] [-c class] [-N ndots] [-R number]\n" 586301759Sdes " %*c [-t type] [-W wait] name [server]\n" 587254939Sdes "\t-a same as -v -t ANY\n" 588254939Sdes "\t-C query SOA records from all authoritative name servers\n" 589254939Sdes "\t-c use this query class (IN, CH, HS, etc)\n" 590254939Sdes "\t-d produce verbose output, same as -v\n" 591254939Sdes "\t-i use IP6.INT for IPv6 reverse lookups\n" 592254939Sdes "\t-l list records in a zone via AXFR\n" 593254939Sdes "\t-N consider names with at least this many dots as absolute\n" 594254939Sdes "\t-R retry UDP queries this many times\n" 595254939Sdes "\t-r disable recursive query\n" 596254939Sdes "\t-s do not ignore SERVFAIL responses\n" 597254939Sdes "\t-T send query via TCP\n" 598254939Sdes "\t-t use this query type (A, AAAA, MX, etc)\n" 599254939Sdes "\t-v produce verbose output\n" 600254939Sdes "\t-w wait forever for a server reply\n" 601254939Sdes "\t-W wait this many seconds for a reply\n" 602254939Sdes "\t-4 use IPv4 only\n" 603254939Sdes "\t-6 use IPv6 only\n", 604301759Sdes progname, (int)strlen(progname), ' '); 605254939Sdes exit(1); 606254939Sdes} 607254939Sdes 608254939Sdesstatic void 609254939Sdesparse_args(int argc, char *argv[]) { 610254939Sdes int ch; 611254939Sdes 612254939Sdes progname = argv[0]; 613254939Sdes while ((ch = getopt(argc, argv, "aCdilrsTvw46c:N:R:t:W:")) != -1) { 614254939Sdes switch (ch) { 615254939Sdes case 'a': 616254939Sdes if (o_mode != M_AXFR) 617254939Sdes o_mode = M_SINGLE_Q; 618254939Sdes o_rrtype = LDNS_RR_TYPE_ANY; 619254939Sdes o_verbose = true; 620254939Sdes break; 621254939Sdes case 'C': 622254939Sdes o_mode = M_SOA; 623254939Sdes o_print_rr_server = true; 624254939Sdes o_rrclass = LDNS_RR_CLASS_IN; 625254939Sdes o_rrtype = LDNS_RR_TYPE_NS; 626254939Sdes break; 627254939Sdes case 'c': 628254939Sdes /* bind9-host sets o_mode to M_SINGLE_Q here */ 629254939Sdes o_rrclass = ldns_get_rr_class_by_name(optarg); 630254939Sdes if (o_rrclass <= 0) 631254939Sdes die(2, "invalid class: %s\n", optarg); 632254939Sdes break; 633254939Sdes case 'd': o_verbose = true; break; 634254939Sdes case 'i': o_ip6_int = true; break; 635254939Sdes case 'l': 636254939Sdes o_mode = M_AXFR; 637301759Sdes if (o_rrtype == (ldns_rr_type)-1) 638301759Sdes o_rrtype = LDNS_RR_TYPE_AXFR; 639254939Sdes o_tcp = true; 640254939Sdes break; 641254939Sdes case 'N': 642254939Sdes o_ndots = atoi(optarg); 643254939Sdes if (o_ndots < 0) o_ndots = 0; 644254939Sdes break; 645254939Sdes case 'n': 646254939Sdes /* bind9-host accepts and ignores this option */ 647254939Sdes break; 648254939Sdes case 'r': o_recursive = 0; break; 649254939Sdes case 'R': 650254939Sdes o_retries = atoi(optarg); 651254939Sdes if (o_retries <= 0) o_retries = 1; 652254939Sdes if (o_retries > 255) o_retries = 255; 653254939Sdes break; 654254939Sdes case 's': o_ignore_servfail = false; break; 655254939Sdes case 'T': o_tcp = true; break; 656254939Sdes case 't': 657254939Sdes if (o_mode != M_AXFR) 658254939Sdes o_mode = M_SINGLE_Q; 659254939Sdes if (strncasecmp(optarg, "ixfr=", 5) == 0) { 660254939Sdes o_rrtype = LDNS_RR_TYPE_IXFR; 661254939Sdes o_ixfr_serial = atol(optarg + 5); 662254939Sdes } else { 663254939Sdes o_rrtype = ldns_get_rr_type_by_name(optarg); 664254939Sdes if (o_rrtype <= 0) 665254939Sdes die(2, "invalid type: %s\n", optarg); 666254939Sdes } 667254939Sdes if (o_rrtype == LDNS_RR_TYPE_AXFR) { 668254939Sdes o_mode = M_AXFR; 669254939Sdes o_rrtype = LDNS_RR_TYPE_ANY; 670254939Sdes o_verbose = true; 671254939Sdes } 672301759Sdes if (o_rrtype == LDNS_RR_TYPE_IXFR) { 673301759Sdes o_mode = M_IXFR; 674301759Sdes o_rrtype = LDNS_RR_TYPE_ANY; 675301759Sdes } 676254939Sdes break; 677254939Sdes case 'v': o_verbose = true; break; 678254939Sdes case 'w': 679254939Sdes o_timeout = (time_t)INT_MAX; 680254939Sdes break; 681254939Sdes case 'W': 682254939Sdes o_timeout = atol(optarg); 683254939Sdes if (o_timeout <= 0) o_timeout = 1; 684254939Sdes break; 685254939Sdes case '4': o_ipversion = LDNS_RESOLV_INET; break; 686254939Sdes case '6': o_ipversion = LDNS_RESOLV_INET6; break; 687254939Sdes default: 688254939Sdes usage(); 689254939Sdes } 690254939Sdes } 691254939Sdes argc -= optind; 692254939Sdes argv += optind; 693254939Sdes /* bind9-host ignores arguments after the 2-nd one */ 694254939Sdes if (argc < 1) 695254939Sdes usage(); 696254939Sdes o_name = argv[0]; 697254939Sdes if (argc > 1) { 698254939Sdes o_server = argv[1]; 699254939Sdes o_print_pkt_server = true; 700254939Sdes } 701301759Sdes if (o_rrtype == (ldns_rr_type)-1) 702301759Sdes o_rrtype = LDNS_RR_TYPE_A; 703254939Sdes} 704254939Sdes 705254939Sdesstatic ldns_rdf* 706254939Sdessafe_str2rdf_dname(const char *name) { 707254939Sdes ldns_rdf *dname; 708254939Sdes ldns_status status; 709254939Sdes 710254939Sdes if ((status = ldns_str2rdf_dname(&dname, name)) != LDNS_STATUS_OK) { 711254939Sdes die(1, "'%s' is not a legal name (%s)", 712254939Sdes name, ldns_get_errorstr_by_id(status)); 713254939Sdes } 714254939Sdes return dname; 715254939Sdes} 716254939Sdes 717254939Sdesstatic ldns_rdf* 718254939Sdessafe_dname_cat_clone(const ldns_rdf *rd1, const ldns_rdf *rd2) { 719254939Sdes ldns_rdf *result = ldns_dname_cat_clone(rd1, rd2); 720254939Sdes 721254939Sdes if (!result) 722254939Sdes die(1, "not enought memory for a domain name"); 723254939Sdes /* Why doesn't ldns_dname_cat_clone check this condition? */ 724254939Sdes if (ldns_rdf_size(result) > LDNS_MAX_DOMAINLEN) 725254939Sdes die(1, "'%s' is not a legal name (%s)\n", ldns_rdf2str(result), 726254939Sdes ldns_get_errorstr_by_id(LDNS_STATUS_DOMAINNAME_OVERFLOW)); 727254939Sdes return result; 728254939Sdes} 729254939Sdes 730254939Sdesstatic bool 731301759Sdesquery(ldns_resolver *res, ldns_rdf *domain, ldns_pkt **pkt, bool close_tcp) { 732254939Sdes ldns_status status; 733254939Sdes ldns_pkt_rcode rcode; 734254939Sdes int i, cnt; 735254939Sdes 736254939Sdes if (o_verbose) { 737254939Sdes printf("Trying \""); 738254939Sdes print_rdf_nodot(domain); 739254939Sdes printf("\"\n"); 740254939Sdes } 741254939Sdes for (cnt = ldns_resolver_nameserver_count(res), i = 0; i < cnt; i++) { 742254939Sdes status = ldns_resolver_send_to(pkt, res, domain, o_rrtype, 743301759Sdes o_rrclass, o_recursive ? LDNS_RD : 0, o_ixfr_serial, i, 744301759Sdes close_tcp); 745254939Sdes if (status != LDNS_STATUS_OK) { 746254939Sdes *pkt = NULL; 747254939Sdes continue; 748254939Sdes } 749254939Sdes if (ldns_pkt_tc(*pkt) && !ldns_resolver_usevc(res)) { 750254939Sdes if (o_verbose) 751254939Sdes printf(";; Truncated, retrying in TCP mode.\n"); 752254939Sdes ldns_resolver_set_usevc(res, true); 753254939Sdes status = ldns_resolver_send_to(pkt, res, domain, o_rrtype, 754301759Sdes o_rrclass, o_recursive ? LDNS_RD : 0, o_ixfr_serial, i, 755301759Sdes close_tcp); 756254939Sdes ldns_resolver_set_usevc(res, false); 757254939Sdes if (status != LDNS_STATUS_OK) 758254939Sdes continue; 759254939Sdes } 760254939Sdes rcode = ldns_pkt_get_rcode(*pkt); 761254939Sdes if (o_ignore_servfail && rcode == LDNS_RCODE_SERVFAIL && cnt > 1) 762254939Sdes continue; 763254939Sdes return rcode == LDNS_RCODE_NOERROR; 764254939Sdes } 765254939Sdes if (*pkt == NULL) { 766254939Sdes printf(";; connection timed out; no servers could be reached\n"); 767254939Sdes exit(1); 768254939Sdes } 769254939Sdes return false; 770254939Sdes} 771254939Sdes 772254939Sdesstatic ldns_rdf * 773301759Sdessearch(ldns_resolver *res, ldns_rdf *domain, ldns_pkt **pkt, 774301759Sdes bool absolute, bool close_tcp) { 775254939Sdes ldns_rdf *dname, **searchlist; 776254939Sdes int i, n; 777254939Sdes 778301759Sdes if (absolute && query(res, domain, pkt, close_tcp)) 779254939Sdes return domain; 780254939Sdes 781254939Sdes if ((dname = ldns_resolver_domain(res)) != NULL) { 782254939Sdes dname = safe_dname_cat_clone(domain, dname); 783301759Sdes if (query(res, dname, pkt, close_tcp)) 784254939Sdes return dname; 785254939Sdes } 786254939Sdes 787254939Sdes searchlist = ldns_resolver_searchlist(res); 788254939Sdes n = ldns_resolver_searchlist_count(res); 789254939Sdes for (i = 0; i < n; i++) { 790254939Sdes dname = safe_dname_cat_clone(domain, searchlist[i]); 791301759Sdes if (query(res, dname, pkt, close_tcp)) 792254939Sdes return dname; 793254939Sdes } 794254939Sdes 795301759Sdes if (!absolute && query(res, domain, pkt, close_tcp)) 796254939Sdes return domain; 797254939Sdes 798254939Sdes return NULL; 799254939Sdes} 800254939Sdes 801254939Sdesstatic void 802254939Sdesreport(ldns_resolver *res, ldns_rdf *domain, ldns_pkt *pkt) { 803254939Sdes ldns_pkt_rcode rcode; 804254939Sdes 805254939Sdes if (o_print_pkt_server) { 806254939Sdes printf("Using domain server:\nName: %s\nAddress: ", o_server); 807254939Sdes print_rdf(ldns_pkt_answerfrom(pkt)); 808254939Sdes printf("#%d\nAliases: \n\n", ldns_resolver_port(res)); 809254939Sdes o_print_pkt_server = false; 810254939Sdes } 811254939Sdes rcode = ldns_pkt_get_rcode(pkt); 812254939Sdes if (rcode != LDNS_RCODE_NOERROR) { 813254939Sdes printf("Host "); 814254939Sdes print_rdf_nodot(domain); 815254939Sdes printf(" not found: %d(", rcode); 816254939Sdes print_rcode(rcode); 817254939Sdes printf(")\n"); 818254939Sdes } else { 819254939Sdes if (o_verbose) { 820254939Sdes print_pkt_verbose(pkt); 821254939Sdes } else { 822254939Sdes print_pkt_short(pkt, o_print_rr_server); 823301759Sdes if (o_mode == M_SINGLE_Q && 824254939Sdes ldns_rr_list_rr_count(ldns_pkt_answer(pkt)) == 0) { 825254939Sdes print_rdf_nodot(domain); 826254939Sdes printf(" has no "); 827254939Sdes print_rr_type(o_rrtype); 828254939Sdes printf(" record\n"); 829254939Sdes } 830254939Sdes } 831254939Sdes } 832254939Sdes if (o_verbose) 833254939Sdes print_received_line(res, pkt); 834254939Sdes} 835254939Sdes 836254939Sdesstatic bool 837254939Sdesdoquery(ldns_resolver *res, ldns_rdf *domain) { 838254939Sdes ldns_pkt *pkt; 839254939Sdes bool q; 840254939Sdes 841301759Sdes q = query(res, domain, &pkt, true); 842254939Sdes report(res, domain, pkt); 843254939Sdes return q; 844254939Sdes} 845254939Sdes 846254939Sdesstatic bool 847254939Sdesdoquery_filtered(ldns_resolver *res, ldns_rdf *domain) { 848254939Sdes ldns_pkt *pkt; 849254939Sdes bool q; 850254939Sdes 851301759Sdes q = query(res, domain, &pkt, true); 852254939Sdes ldns_pkt_filter_answer(pkt, o_rrtype); 853254939Sdes report(res, domain, pkt); 854254939Sdes return q; 855254939Sdes} 856254939Sdes 857254939Sdesstatic bool 858254939Sdesdosearch(ldns_resolver *res, ldns_rdf *domain, bool absolute) { 859254939Sdes ldns_pkt *pkt; 860254939Sdes ldns_rdf *dname; 861254939Sdes 862301759Sdes dname = search(res, domain, &pkt, absolute, true); 863254939Sdes report(res, dname != NULL ? dname : domain, pkt); 864254939Sdes return o_mode != M_DEFAULT_Q ? (dname != NULL) : 865254939Sdes (dname != NULL) && 866254939Sdes (o_rrtype = LDNS_RR_TYPE_AAAA, doquery_filtered(res, dname)) && 867254939Sdes (o_rrtype = LDNS_RR_TYPE_MX, doquery_filtered(res, dname)); 868254939Sdes} 869254939Sdes 870254939Sdesstatic bool 871301759Sdesdozonetransfer(ldns_resolver *res, ldns_rdf *domain, bool absolute) { 872301759Sdes ldns_pkt *pkt, *nextpkt; 873254939Sdes ldns_rdf *dname; 874254939Sdes ldns_rr_type rrtype; 875301759Sdes ldns_rr_list *rrl; 876301759Sdes int i, nsoa = 0; 877254939Sdes 878254939Sdes rrtype = o_rrtype; 879301759Sdes o_rrtype = (o_mode == M_AXFR) ? LDNS_RR_TYPE_AXFR : LDNS_RR_TYPE_IXFR; 880301759Sdes dname = search(res, domain, &pkt, absolute, false); 881301759Sdes 882301759Sdes for (;;) { 883301759Sdes rrl = ldns_pkt_answer(pkt); 884301759Sdes for (i = ldns_rr_list_rr_count(rrl) - 1; i >= 0; i--) { 885301759Sdes if (ldns_rr_get_type(ldns_rr_list_rr(rrl, i)) == LDNS_RR_TYPE_SOA) 886301759Sdes nsoa++; 887301759Sdes } 888301759Sdes ldns_pkt_filter_answer(pkt, rrtype); 889301759Sdes report(res, dname != NULL ? dname : domain, pkt); 890301759Sdes if ((dname == NULL) || 891301759Sdes (ldns_pkt_get_rcode(pkt) != LDNS_RCODE_NOERROR)) { 892301759Sdes printf("; Transfer failed.\n"); 893301759Sdes ldns_tcp_close(res); 894301759Sdes return false; 895301759Sdes } 896301759Sdes if (nsoa >= 2) { 897301759Sdes ldns_tcp_close(res); 898301759Sdes return true; 899301759Sdes } 900301759Sdes if (ldns_tcp_read(&nextpkt, res) != LDNS_STATUS_OK) { 901301759Sdes printf("; Transfer failed.\n"); 902301759Sdes return false; 903301759Sdes } 904301759Sdes ldns_pkt_set_answerfrom(nextpkt, 905301759Sdes ldns_rdf_clone(ldns_pkt_answerfrom(pkt))); 906301759Sdes ldns_pkt_free(pkt); 907301759Sdes pkt = nextpkt; 908301759Sdes } 909254939Sdes} 910254939Sdes 911254939Sdesstatic bool 912254939Sdesdosoa(ldns_resolver *res, ldns_rdf *domain, bool absolute) { 913254939Sdes ldns_rr_list *answer, **nsaddrs; 914254939Sdes ldns_rdf *dname, *addr; 915254939Sdes ldns_pkt *pkt; 916254939Sdes ldns_rr *rr; 917254939Sdes size_t i, j, n, cnt; 918254939Sdes 919301759Sdes if ((dname = search(res, domain, &pkt, absolute, true)) == NULL) 920254939Sdes return false; 921254939Sdes 922254939Sdes answer = ldns_pkt_answer(pkt); 923254939Sdes cnt = ldns_rr_list_rr_count(answer); 924254939Sdes nsaddrs = alloca(cnt*sizeof(*nsaddrs)); 925254939Sdes for (n = 0, i = 0; i < cnt; i++) 926254939Sdes if ((addr = ldns_rr_ns_nsdname(ldns_rr_list_rr(answer, i))) != NULL) 927254939Sdes nsaddrs[n++] = ldns_get_rr_list_addr_by_name(res, 928254939Sdes addr, LDNS_RR_CLASS_IN, 0); 929254939Sdes 930254939Sdes o_print_pkt_server = false; 931254939Sdes o_recursive = false; 932254939Sdes o_rrtype = LDNS_RR_TYPE_SOA; 933254939Sdes for (i = 0; i < n; i++) { 934254939Sdes cnt = ldns_rr_list_rr_count(nsaddrs[i]); 935254939Sdes for (j = 0; j < cnt; j++) { 936254939Sdes ldns_resolver_remove_nameservers(res); 937254939Sdes rr = ldns_rr_list_rr(nsaddrs[i], j); 938255403Sdes if ((ldns_resolver_ip6(res) == LDNS_RESOLV_INET && 939301759Sdes ldns_rr_get_type(rr) == LDNS_RR_TYPE_AAAA) || 940255403Sdes (ldns_resolver_ip6(res) == LDNS_RESOLV_INET6 && 941301759Sdes ldns_rr_get_type(rr) == LDNS_RR_TYPE_A)) 942254939Sdes continue; 943254939Sdes if (ldns_resolver_push_nameserver_rr(res, rr) == LDNS_STATUS_OK) 944254939Sdes /* bind9-host queries for domain, not dname here */ 945254939Sdes doquery(res, dname); 946254939Sdes } 947254939Sdes } 948254939Sdes return 0; 949254939Sdes} 950254939Sdes 951254939Sdesstatic void 952254939Sdesresolver_set_nameserver_hostname(ldns_resolver *res, const char *server) { 953254939Sdes struct addrinfo hints, *ailist, *ai; 954254939Sdes ldns_status status; 955254939Sdes ldns_rdf *rdf; 956254939Sdes int err; 957254939Sdes 958254939Sdes memset(&hints, 0, sizeof hints); 959254939Sdes switch (ldns_resolver_ip6(res)) { 960254939Sdes case LDNS_RESOLV_INET: hints.ai_family = PF_INET; break; 961254939Sdes case LDNS_RESOLV_INET6: hints.ai_family = PF_INET6; break; 962254939Sdes default: hints.ai_family = PF_UNSPEC; break; 963254939Sdes } 964254939Sdes hints.ai_socktype = SOCK_STREAM; 965254939Sdes do err = getaddrinfo(server, NULL, &hints, &ailist); 966254939Sdes while (err == EAI_AGAIN); 967254939Sdes if (err != 0) 968254939Sdes die(1, "couldn't get address for '%s': %s", server, gai_strerror(err)); 969254939Sdes for (ai = ailist; ai != NULL; ai = ai->ai_next) { 970254939Sdes if ((rdf = ldns_sockaddr_storage2rdf((void*)ai->ai_addr, NULL)) == NULL) 971254939Sdes die(1, "couldn't allocate an rdf: %s", 972254939Sdes ldns_get_errorstr_by_id(LDNS_STATUS_MEM_ERR)); 973254939Sdes status = ldns_resolver_push_nameserver(res, rdf); 974254939Sdes if (status != LDNS_STATUS_OK) 975254939Sdes die(1, "couldn't push a nameserver address: %s", 976254939Sdes ldns_get_errorstr_by_id(status)); 977254939Sdes } 978254939Sdes} 979254939Sdes 980254939Sdesstatic void 981254939Sdesresolver_set_nameserver_str(ldns_resolver *res, const char *server) { 982254939Sdes ldns_rdf *addr; 983254939Sdes 984254939Sdes ldns_resolver_remove_nameservers(res); 985254939Sdes addr = ldns_rdf_new_addr_frm_str(server); 986254939Sdes if (addr) { 987254939Sdes if (ldns_resolver_push_nameserver(res, addr) != LDNS_STATUS_OK) 988254939Sdes die(1, "couldn't push a nameserver address"); 989254939Sdes } else 990254939Sdes resolver_set_nameserver_hostname(res, server); 991254939Sdes} 992254939Sdes 993254939Sdesint 994254939Sdesmain(int argc, char *argv[]) { 995254939Sdes ldns_rdf *addr, *dname; 996254939Sdes ldns_resolver *res; 997254939Sdes ldns_status status; 998254939Sdes struct timeval restimeout; 999254939Sdes 1000254939Sdes parse_args(argc, argv); 1001254939Sdes 1002254939Sdes status = ldns_resolver_new_default(&res); 1003254939Sdes if (status != LDNS_STATUS_OK) 1004254939Sdes die(1, "error creating resolver: %s", ldns_get_errorstr_by_id(status)); 1005254939Sdes if (ldns_resolver_nameserver_count(res) == 0) 1006254939Sdes ldns_resolver_push_default_servers(res); 1007254939Sdes 1008254939Sdes ldns_resolver_set_usevc(res, o_tcp); 1009254939Sdes restimeout.tv_sec = o_timeout > 0 ? o_timeout : 1010254939Sdes o_tcp ? DEFAULT_TCP_TIMEOUT : DEFAULT_UDP_TIMEOUT; 1011254939Sdes restimeout.tv_usec = 0; 1012254939Sdes ldns_resolver_set_timeout(res, restimeout); 1013254939Sdes ldns_resolver_set_retry(res, o_retries+1); 1014254939Sdes ldns_resolver_set_ip6(res, o_ipversion); 1015254939Sdes ldns_resolver_set_defnames(res, false); 1016254939Sdes ldns_resolver_set_fallback(res, false); 1017254939Sdes 1018254939Sdes if (o_server) 1019254939Sdes resolver_set_nameserver_str(res, o_server); 1020254939Sdes 1021254939Sdes if (ldns_str2rdf_a(&addr, o_name) == LDNS_STATUS_OK) { 1022254939Sdes dname = ldns_rdf_reverse_a(addr, "in-addr.arpa"); 1023254939Sdes if (dname == NULL) 1024254939Sdes die(1, "can't reverse '%s': %s", o_name, 1025254939Sdes ldns_get_errorstr_by_id(LDNS_STATUS_MEM_ERR)); 1026254939Sdes o_mode = M_SINGLE_Q; 1027254939Sdes o_rrtype = LDNS_RR_TYPE_PTR; 1028254939Sdes return !doquery(res, dname); 1029254939Sdes } else if (ldns_str2rdf_aaaa(&addr, o_name) == LDNS_STATUS_OK) { 1030254939Sdes dname = ldns_rdf_reverse_aaaa(addr, o_ip6_int ? "ip6.int" : "ip6.arpa"); 1031254939Sdes if (dname == NULL) 1032254939Sdes die(1, "can't reverse '%s': %s", o_name, 1033254939Sdes ldns_get_errorstr_by_id(LDNS_STATUS_MEM_ERR)); 1034254939Sdes o_mode = M_SINGLE_Q; 1035254939Sdes o_rrtype = LDNS_RR_TYPE_PTR; 1036254939Sdes return !doquery(res, dname); 1037254939Sdes } 1038301759Sdes return !(o_mode == M_SOA ? dosoa : 1039301759Sdes o_mode == M_AXFR ? dozonetransfer : 1040301759Sdes o_mode == M_IXFR ? dozonetransfer : 1041301759Sdes dosearch) 1042254939Sdes (res, safe_str2rdf_dname(o_name), ndots(o_name) >= o_ndots); 1043254939Sdes} 1044