13fc9e2c3SDag-Erling Smørgrav /*- 23fc9e2c3SDag-Erling Smørgrav * (c) Magerya Vitaly 33fc9e2c3SDag-Erling Smørgrav * 43fc9e2c3SDag-Erling Smørgrav * Copying and distribution of this file, with or without modification, 53fc9e2c3SDag-Erling Smørgrav * are permitted in any medium without royalty provided the copyright 63fc9e2c3SDag-Erling Smørgrav * notice and this notice are preserved. This file is offered as-is, 73fc9e2c3SDag-Erling Smørgrav * without any warranty. 83fc9e2c3SDag-Erling Smørgrav */ 93fc9e2c3SDag-Erling Smørgrav 10*3f68b24eSDag-Erling Smørgrav #include <ldns/ldns.h> 113fc9e2c3SDag-Erling Smørgrav #include <limits.h> 123fc9e2c3SDag-Erling Smørgrav #include <netdb.h> 13*3f68b24eSDag-Erling Smørgrav #include <netinet/in.h> 143fc9e2c3SDag-Erling Smørgrav #include <stdio.h> 153fc9e2c3SDag-Erling Smørgrav #include <stdlib.h> 163fc9e2c3SDag-Erling Smørgrav #include <unistd.h> 173fc9e2c3SDag-Erling Smørgrav 183fc9e2c3SDag-Erling Smørgrav /* General utilities. 193fc9e2c3SDag-Erling Smørgrav */ 203fc9e2c3SDag-Erling Smørgrav 213fc9e2c3SDag-Erling Smørgrav static char *progname; 223fc9e2c3SDag-Erling Smørgrav 233fc9e2c3SDag-Erling Smørgrav #define countof(array) (sizeof(array)/sizeof(*(array))) 243fc9e2c3SDag-Erling Smørgrav 253fc9e2c3SDag-Erling Smørgrav static void 263fc9e2c3SDag-Erling Smørgrav die(int code, const char *fmt, ...) { 273fc9e2c3SDag-Erling Smørgrav va_list args; 283fc9e2c3SDag-Erling Smørgrav 293fc9e2c3SDag-Erling Smørgrav va_start(args, fmt); 303fc9e2c3SDag-Erling Smørgrav fprintf(stderr, "%s: ", progname); 313fc9e2c3SDag-Erling Smørgrav vfprintf(stderr, fmt, args); 323fc9e2c3SDag-Erling Smørgrav fprintf(stderr, "\n"); 333fc9e2c3SDag-Erling Smørgrav va_end(args); 343fc9e2c3SDag-Erling Smørgrav exit(code); 353fc9e2c3SDag-Erling Smørgrav } 363fc9e2c3SDag-Erling Smørgrav 373fc9e2c3SDag-Erling Smørgrav static int 383fc9e2c3SDag-Erling Smørgrav ndots(const char *name) { 393fc9e2c3SDag-Erling Smørgrav int n; 403fc9e2c3SDag-Erling Smørgrav 413fc9e2c3SDag-Erling Smørgrav for (n = 0; (name = strchr(name, '.')); n++, name++); 423fc9e2c3SDag-Erling Smørgrav return n; 433fc9e2c3SDag-Erling Smørgrav } 443fc9e2c3SDag-Erling Smørgrav 453fc9e2c3SDag-Erling Smørgrav /* General LDNS-specific utilities. 463fc9e2c3SDag-Erling Smørgrav */ 473fc9e2c3SDag-Erling Smørgrav 483fc9e2c3SDag-Erling Smørgrav static ldns_status 493fc9e2c3SDag-Erling Smørgrav ldns_resolver_new_default(ldns_resolver **res) { 503fc9e2c3SDag-Erling Smørgrav if (ldns_resolver_new_frm_file(res, NULL) == LDNS_STATUS_OK || 513fc9e2c3SDag-Erling Smørgrav (*res = ldns_resolver_new()) != NULL) 523fc9e2c3SDag-Erling Smørgrav return LDNS_STATUS_OK; 533fc9e2c3SDag-Erling Smørgrav return LDNS_STATUS_MEM_ERR; 543fc9e2c3SDag-Erling Smørgrav } 553fc9e2c3SDag-Erling Smørgrav 563fc9e2c3SDag-Erling Smørgrav static ldns_status 573fc9e2c3SDag-Erling Smørgrav ldns_resolver_push_default_servers(ldns_resolver *res) { 583fc9e2c3SDag-Erling Smørgrav ldns_status status; 593fc9e2c3SDag-Erling Smørgrav ldns_rdf *addr; 603fc9e2c3SDag-Erling Smørgrav 613fc9e2c3SDag-Erling Smørgrav if ((status = ldns_str2rdf_a(&addr, "127.0.0.1")) != LDNS_STATUS_OK || 623fc9e2c3SDag-Erling Smørgrav (status = ldns_resolver_push_nameserver(res, addr)) != LDNS_STATUS_OK) 633fc9e2c3SDag-Erling Smørgrav return ldns_rdf_deep_free(addr), status; 643fc9e2c3SDag-Erling Smørgrav ldns_rdf_deep_free(addr); 653fc9e2c3SDag-Erling Smørgrav if ((status = ldns_str2rdf_aaaa(&addr, "::1")) != LDNS_STATUS_OK || 663fc9e2c3SDag-Erling Smørgrav (status = ldns_resolver_push_nameserver(res, addr)) != LDNS_STATUS_OK) 673fc9e2c3SDag-Erling Smørgrav return ldns_rdf_deep_free(addr), status; 683fc9e2c3SDag-Erling Smørgrav ldns_rdf_deep_free(addr); 693fc9e2c3SDag-Erling Smørgrav return LDNS_STATUS_OK; 703fc9e2c3SDag-Erling Smørgrav } 713fc9e2c3SDag-Erling Smørgrav 723fc9e2c3SDag-Erling Smørgrav static ldns_rdf * 733fc9e2c3SDag-Erling Smørgrav ldns_rdf_new_addr_frm_str(const char *str) { 743fc9e2c3SDag-Erling Smørgrav ldns_rdf *addr; 753fc9e2c3SDag-Erling Smørgrav 763fc9e2c3SDag-Erling Smørgrav if ((addr = ldns_rdf_new_frm_str(LDNS_RDF_TYPE_A, str)) == NULL) 773fc9e2c3SDag-Erling Smørgrav addr = ldns_rdf_new_frm_str(LDNS_RDF_TYPE_AAAA, str); 783fc9e2c3SDag-Erling Smørgrav return addr; 793fc9e2c3SDag-Erling Smørgrav } 803fc9e2c3SDag-Erling Smørgrav 813fc9e2c3SDag-Erling Smørgrav static void 823fc9e2c3SDag-Erling Smørgrav ldns_resolver_remove_nameservers(ldns_resolver *res) { 833fc9e2c3SDag-Erling Smørgrav while (ldns_resolver_nameserver_count(res) > 0) 843fc9e2c3SDag-Erling Smørgrav ldns_rdf_deep_free(ldns_resolver_pop_nameserver(res)); 853fc9e2c3SDag-Erling Smørgrav } 863fc9e2c3SDag-Erling Smørgrav 873fc9e2c3SDag-Erling Smørgrav static ldns_rdf * 883fc9e2c3SDag-Erling Smørgrav ldns_rdf_reverse_a(ldns_rdf *addr, const char *base) { 893fc9e2c3SDag-Erling Smørgrav char *buf; 903fc9e2c3SDag-Erling Smørgrav int i, len; 913fc9e2c3SDag-Erling Smørgrav 923fc9e2c3SDag-Erling Smørgrav len = strlen(base); 933fc9e2c3SDag-Erling Smørgrav buf = alloca(LDNS_IP4ADDRLEN*4 + len + 1); 943fc9e2c3SDag-Erling Smørgrav for (len = i = 0; i < LDNS_IP4ADDRLEN; i++) 953fc9e2c3SDag-Erling Smørgrav len += sprintf(&buf[len], "%d.", 963fc9e2c3SDag-Erling Smørgrav (int)ldns_rdf_data(addr)[LDNS_IP4ADDRLEN - i - 1]); 973fc9e2c3SDag-Erling Smørgrav sprintf(&buf[len], "%s", base); 983fc9e2c3SDag-Erling Smørgrav return ldns_dname_new_frm_str(buf); 993fc9e2c3SDag-Erling Smørgrav } 1003fc9e2c3SDag-Erling Smørgrav 1013fc9e2c3SDag-Erling Smørgrav static ldns_rdf * 1023fc9e2c3SDag-Erling Smørgrav ldns_rdf_reverse_aaaa(ldns_rdf *addr, const char *base) { 1033fc9e2c3SDag-Erling Smørgrav char *buf; 1043fc9e2c3SDag-Erling Smørgrav int i, len; 1053fc9e2c3SDag-Erling Smørgrav 1063fc9e2c3SDag-Erling Smørgrav len = strlen(base); 1073fc9e2c3SDag-Erling Smørgrav buf = alloca(LDNS_IP6ADDRLEN*4 + len + 1); 1083fc9e2c3SDag-Erling Smørgrav for (i = 0; i < LDNS_IP6ADDRLEN; i++) { 1093fc9e2c3SDag-Erling Smørgrav uint8_t byte = ldns_rdf_data(addr)[LDNS_IP6ADDRLEN - i - 1]; 1103fc9e2c3SDag-Erling Smørgrav sprintf(&buf[i*4], "%x.%x.", byte & 0x0F, byte >> 4); 1113fc9e2c3SDag-Erling Smørgrav } 1123fc9e2c3SDag-Erling Smørgrav sprintf(&buf[LDNS_IP6ADDRLEN*4], "%s", base); 1133fc9e2c3SDag-Erling Smørgrav return ldns_dname_new_frm_str(buf); 1143fc9e2c3SDag-Erling Smørgrav } 1153fc9e2c3SDag-Erling Smørgrav 1163fc9e2c3SDag-Erling Smørgrav static ldns_status 1173fc9e2c3SDag-Erling Smørgrav ldns_pkt_push_rr_soa(ldns_pkt *pkt, ldns_pkt_section sec, 1183fc9e2c3SDag-Erling Smørgrav const ldns_rdf *name, ldns_rr_class c, uint32_t serial) { 1193fc9e2c3SDag-Erling Smørgrav ldns_rdf *rdf; 1203fc9e2c3SDag-Erling Smørgrav ldns_rr *rr; 1213fc9e2c3SDag-Erling Smørgrav uint32_t n; 1223fc9e2c3SDag-Erling Smørgrav 1233fc9e2c3SDag-Erling Smørgrav if ((rr = ldns_rr_new_frm_type(LDNS_RR_TYPE_SOA)) == NULL) 1243fc9e2c3SDag-Erling Smørgrav return LDNS_STATUS_MEM_ERR; 1253fc9e2c3SDag-Erling Smørgrav ldns_rr_set_class(rr, c); 1263fc9e2c3SDag-Erling Smørgrav ldns_rr_set_owner(rr, ldns_rdf_clone(name)); 1273fc9e2c3SDag-Erling Smørgrav ldns_rr_set_ttl(rr, 0); 1283fc9e2c3SDag-Erling Smørgrav 1293fc9e2c3SDag-Erling Smørgrav n = 0; 1303fc9e2c3SDag-Erling Smørgrav if ((rdf = ldns_rdf_new_frm_data(LDNS_RDF_TYPE_DNAME, 1, &n)) == NULL) 1313fc9e2c3SDag-Erling Smørgrav goto memerr; 1323fc9e2c3SDag-Erling Smørgrav ldns_rr_set_rdf(rr, rdf, 0); 1333fc9e2c3SDag-Erling Smørgrav ldns_rr_set_rdf(rr, ldns_rdf_clone(rdf), 1); 1343fc9e2c3SDag-Erling Smørgrav 1353fc9e2c3SDag-Erling Smørgrav n = htonl(serial); 1363fc9e2c3SDag-Erling Smørgrav if ((rdf = ldns_rdf_new_frm_data(LDNS_RDF_TYPE_INT32, 4, &n)) == NULL) 1373fc9e2c3SDag-Erling Smørgrav goto memerr; 1383fc9e2c3SDag-Erling Smørgrav ldns_rr_set_rdf(rr, rdf, 2); 1393fc9e2c3SDag-Erling Smørgrav 1403fc9e2c3SDag-Erling Smørgrav n = 0; 1413fc9e2c3SDag-Erling Smørgrav if ((rdf = ldns_rdf_new_frm_data(LDNS_RDF_TYPE_PERIOD, 4, &n)) == NULL) 1423fc9e2c3SDag-Erling Smørgrav goto memerr; 1433fc9e2c3SDag-Erling Smørgrav ldns_rr_set_rdf(rr, rdf, 3); 1443fc9e2c3SDag-Erling Smørgrav ldns_rr_set_rdf(rr, ldns_rdf_clone(rdf), 4); 1453fc9e2c3SDag-Erling Smørgrav ldns_rr_set_rdf(rr, ldns_rdf_clone(rdf), 5); 1463fc9e2c3SDag-Erling Smørgrav ldns_rr_set_rdf(rr, ldns_rdf_clone(rdf), 6); 1473fc9e2c3SDag-Erling Smørgrav 1483fc9e2c3SDag-Erling Smørgrav if (ldns_rr_rdf(rr, 1) == NULL || ldns_rr_rdf(rr, 4) == NULL || 1493fc9e2c3SDag-Erling Smørgrav ldns_rr_rdf(rr, 5) == NULL || ldns_rr_rdf(rr, 6) == NULL || 1503fc9e2c3SDag-Erling Smørgrav !ldns_pkt_push_rr(pkt, sec, rr)) 1513fc9e2c3SDag-Erling Smørgrav goto memerr; 1523fc9e2c3SDag-Erling Smørgrav return LDNS_STATUS_OK; 1533fc9e2c3SDag-Erling Smørgrav 1543fc9e2c3SDag-Erling Smørgrav memerr: 1553fc9e2c3SDag-Erling Smørgrav ldns_rr_free(rr); 1563fc9e2c3SDag-Erling Smørgrav return LDNS_STATUS_MEM_ERR; 1573fc9e2c3SDag-Erling Smørgrav } 1583fc9e2c3SDag-Erling Smørgrav 1593fc9e2c3SDag-Erling Smørgrav static ldns_status 160*3f68b24eSDag-Erling Smørgrav ldns_tcp_start(ldns_resolver *res, ldns_pkt *qpkt, int nameserver) { 161*3f68b24eSDag-Erling Smørgrav /* This routine is based on ldns_axfr_start, with the major 162*3f68b24eSDag-Erling Smørgrav * difference in that it takes a query packet explicitly. 163*3f68b24eSDag-Erling Smørgrav */ 164*3f68b24eSDag-Erling Smørgrav struct sockaddr_storage *ns = NULL; 165*3f68b24eSDag-Erling Smørgrav size_t ns_len = 0; 166*3f68b24eSDag-Erling Smørgrav ldns_buffer *qbuf = NULL; 167*3f68b24eSDag-Erling Smørgrav ldns_status status; 168*3f68b24eSDag-Erling Smørgrav 169*3f68b24eSDag-Erling Smørgrav ns = ldns_rdf2native_sockaddr_storage( 170*3f68b24eSDag-Erling Smørgrav res->_nameservers[nameserver], ldns_resolver_port(res), &ns_len); 171*3f68b24eSDag-Erling Smørgrav if (ns == NULL) { 172*3f68b24eSDag-Erling Smørgrav status = LDNS_STATUS_MEM_ERR; 173*3f68b24eSDag-Erling Smørgrav goto error; 174*3f68b24eSDag-Erling Smørgrav } 175*3f68b24eSDag-Erling Smørgrav 176*3f68b24eSDag-Erling Smørgrav res->_socket = ldns_tcp_connect( 177*3f68b24eSDag-Erling Smørgrav ns, (socklen_t)ns_len, ldns_resolver_timeout(res)); 178*3f68b24eSDag-Erling Smørgrav if (res->_socket <= 0) { 179*3f68b24eSDag-Erling Smørgrav status = LDNS_STATUS_ADDRESS_ERR; 180*3f68b24eSDag-Erling Smørgrav goto error; 181*3f68b24eSDag-Erling Smørgrav } 182*3f68b24eSDag-Erling Smørgrav 183*3f68b24eSDag-Erling Smørgrav qbuf = ldns_buffer_new(LDNS_MAX_PACKETLEN); 184*3f68b24eSDag-Erling Smørgrav if (qbuf == NULL) { 185*3f68b24eSDag-Erling Smørgrav status = LDNS_STATUS_MEM_ERR; 186*3f68b24eSDag-Erling Smørgrav goto error; 187*3f68b24eSDag-Erling Smørgrav } 188*3f68b24eSDag-Erling Smørgrav 189*3f68b24eSDag-Erling Smørgrav status = ldns_pkt2buffer_wire(qbuf, qpkt); 190*3f68b24eSDag-Erling Smørgrav if (status != LDNS_STATUS_OK) 191*3f68b24eSDag-Erling Smørgrav goto error; 192*3f68b24eSDag-Erling Smørgrav 193*3f68b24eSDag-Erling Smørgrav if (ldns_tcp_send_query(qbuf, res->_socket, ns, (socklen_t)ns_len) == 0) { 194*3f68b24eSDag-Erling Smørgrav status = LDNS_STATUS_NETWORK_ERR; 195*3f68b24eSDag-Erling Smørgrav goto error; 196*3f68b24eSDag-Erling Smørgrav } 197*3f68b24eSDag-Erling Smørgrav 198*3f68b24eSDag-Erling Smørgrav ldns_buffer_free(qbuf); 199*3f68b24eSDag-Erling Smørgrav free(ns); 200*3f68b24eSDag-Erling Smørgrav return LDNS_STATUS_OK; 201*3f68b24eSDag-Erling Smørgrav 202*3f68b24eSDag-Erling Smørgrav error: 203*3f68b24eSDag-Erling Smørgrav ldns_buffer_free(qbuf); 204*3f68b24eSDag-Erling Smørgrav free(ns); 205*3f68b24eSDag-Erling Smørgrav if (res->_socket > 0) { 206*3f68b24eSDag-Erling Smørgrav close(res->_socket); 207*3f68b24eSDag-Erling Smørgrav res->_socket = 0; 208*3f68b24eSDag-Erling Smørgrav } 209*3f68b24eSDag-Erling Smørgrav return status; 210*3f68b24eSDag-Erling Smørgrav } 211*3f68b24eSDag-Erling Smørgrav 212*3f68b24eSDag-Erling Smørgrav static ldns_status 213*3f68b24eSDag-Erling Smørgrav ldns_tcp_read(ldns_pkt **answer, ldns_resolver *res) { 214*3f68b24eSDag-Erling Smørgrav ldns_status status; 215*3f68b24eSDag-Erling Smørgrav struct timeval t1, t2; 216*3f68b24eSDag-Erling Smørgrav uint8_t *data; 217*3f68b24eSDag-Erling Smørgrav size_t size; 218*3f68b24eSDag-Erling Smørgrav 219*3f68b24eSDag-Erling Smørgrav if (res->_socket <= 0) 220*3f68b24eSDag-Erling Smørgrav return LDNS_STATUS_ERR; 221*3f68b24eSDag-Erling Smørgrav 222*3f68b24eSDag-Erling Smørgrav gettimeofday(&t1, NULL); 223*3f68b24eSDag-Erling Smørgrav data = ldns_tcp_read_wire_timeout( 224*3f68b24eSDag-Erling Smørgrav res->_socket, &size, ldns_resolver_timeout(res)); 225*3f68b24eSDag-Erling Smørgrav if (data == NULL) 226*3f68b24eSDag-Erling Smørgrav goto error; 227*3f68b24eSDag-Erling Smørgrav 228*3f68b24eSDag-Erling Smørgrav status = ldns_wire2pkt(answer, data, size); 229*3f68b24eSDag-Erling Smørgrav free(data); 230*3f68b24eSDag-Erling Smørgrav if (status != LDNS_STATUS_OK) 231*3f68b24eSDag-Erling Smørgrav goto error; 232*3f68b24eSDag-Erling Smørgrav 233*3f68b24eSDag-Erling Smørgrav gettimeofday(&t2, NULL); 234*3f68b24eSDag-Erling Smørgrav ldns_pkt_set_querytime(*answer, 235*3f68b24eSDag-Erling Smørgrav (uint32_t)((t2.tv_sec - t1.tv_sec)*1000) + 236*3f68b24eSDag-Erling Smørgrav (t2.tv_usec - t1.tv_usec)/1000); 237*3f68b24eSDag-Erling Smørgrav ldns_pkt_set_timestamp(*answer, t2); 238*3f68b24eSDag-Erling Smørgrav return status; 239*3f68b24eSDag-Erling Smørgrav 240*3f68b24eSDag-Erling Smørgrav error: 241*3f68b24eSDag-Erling Smørgrav close(res->_socket); 242*3f68b24eSDag-Erling Smørgrav res->_socket = 0; 243*3f68b24eSDag-Erling Smørgrav return LDNS_STATUS_ERR; 244*3f68b24eSDag-Erling Smørgrav } 245*3f68b24eSDag-Erling Smørgrav 246*3f68b24eSDag-Erling Smørgrav static void 247*3f68b24eSDag-Erling Smørgrav ldns_tcp_close(ldns_resolver *res) { 248*3f68b24eSDag-Erling Smørgrav if (res->_socket > 0) { 249*3f68b24eSDag-Erling Smørgrav close(res->_socket); 250*3f68b24eSDag-Erling Smørgrav res->_socket = 0; 251*3f68b24eSDag-Erling Smørgrav } 252*3f68b24eSDag-Erling Smørgrav } 253*3f68b24eSDag-Erling Smørgrav 254*3f68b24eSDag-Erling Smørgrav static ldns_status 2553fc9e2c3SDag-Erling Smørgrav ldns_resolver_send_to(ldns_pkt **answer, ldns_resolver *res, 2563fc9e2c3SDag-Erling Smørgrav const ldns_rdf *name, ldns_rr_type t, ldns_rr_class c, 257*3f68b24eSDag-Erling Smørgrav uint16_t flags, uint32_t ixfr_serial, int nameserver, 258*3f68b24eSDag-Erling Smørgrav bool close_tcp) { 259*3f68b24eSDag-Erling Smørgrav ldns_status status = LDNS_STATUS_OK; 2603fc9e2c3SDag-Erling Smørgrav ldns_pkt *qpkt; 261*3f68b24eSDag-Erling Smørgrav struct timeval now; 2623fc9e2c3SDag-Erling Smørgrav 2633fc9e2c3SDag-Erling Smørgrav int nscnt = ldns_resolver_nameserver_count(res); 2643fc9e2c3SDag-Erling Smørgrav ldns_rdf **ns = ldns_resolver_nameservers(res); 2653fc9e2c3SDag-Erling Smørgrav size_t *rtt = ldns_resolver_rtt(res); 2663fc9e2c3SDag-Erling Smørgrav 2673fc9e2c3SDag-Erling Smørgrav ldns_resolver_set_nameservers(res, &ns[nameserver]); 2683fc9e2c3SDag-Erling Smørgrav ldns_resolver_set_rtt(res, &rtt[nameserver]); 2693fc9e2c3SDag-Erling Smørgrav ldns_resolver_set_nameserver_count(res, 1); 2703fc9e2c3SDag-Erling Smørgrav 271*3f68b24eSDag-Erling Smørgrav /* The next fragment should have been a call to 272*3f68b24eSDag-Erling Smørgrav * ldns_resolver_prepare_query_pkt(), but starting with ldns 273*3f68b24eSDag-Erling Smørgrav * version 1.6.17 that function tries to add it's own SOA 274*3f68b24eSDag-Erling Smørgrav * records when rr_type is LDNS_RR_TYPE_IXFR, and we don't 275*3f68b24eSDag-Erling Smørgrav * want that. 276*3f68b24eSDag-Erling Smørgrav */ 277*3f68b24eSDag-Erling Smørgrav qpkt = ldns_pkt_query_new(ldns_rdf_clone(name), t, c, flags); 278*3f68b24eSDag-Erling Smørgrav if (qpkt == NULL) { 279*3f68b24eSDag-Erling Smørgrav status = LDNS_STATUS_ERR; 280*3f68b24eSDag-Erling Smørgrav goto done; 281*3f68b24eSDag-Erling Smørgrav } 282*3f68b24eSDag-Erling Smørgrav now.tv_sec = time(NULL); 283*3f68b24eSDag-Erling Smørgrav now.tv_usec = 0; 284*3f68b24eSDag-Erling Smørgrav ldns_pkt_set_timestamp(qpkt, now); 285*3f68b24eSDag-Erling Smørgrav ldns_pkt_set_random_id(qpkt); 286*3f68b24eSDag-Erling Smørgrav 287*3f68b24eSDag-Erling Smørgrav if (t == LDNS_RR_TYPE_IXFR) { 2883fc9e2c3SDag-Erling Smørgrav status = ldns_pkt_push_rr_soa(qpkt, 2893fc9e2c3SDag-Erling Smørgrav LDNS_SECTION_AUTHORITY, name, c, ixfr_serial); 290*3f68b24eSDag-Erling Smørgrav if (status != LDNS_STATUS_OK) goto done; 291*3f68b24eSDag-Erling Smørgrav } 292*3f68b24eSDag-Erling Smørgrav if (close_tcp) { 2933fc9e2c3SDag-Erling Smørgrav status = ldns_resolver_send_pkt(answer, res, qpkt); 294*3f68b24eSDag-Erling Smørgrav } else { 295*3f68b24eSDag-Erling Smørgrav status = ldns_tcp_start(res, qpkt, 0); 296*3f68b24eSDag-Erling Smørgrav if (status != LDNS_STATUS_OK) goto done; 297*3f68b24eSDag-Erling Smørgrav status = ldns_tcp_read(answer, res); 298*3f68b24eSDag-Erling Smørgrav if (status != LDNS_STATUS_OK) goto done; 299*3f68b24eSDag-Erling Smørgrav ldns_pkt_set_answerfrom(*answer, ldns_rdf_clone(ns[0])); 300*3f68b24eSDag-Erling Smørgrav } 301*3f68b24eSDag-Erling Smørgrav 302*3f68b24eSDag-Erling Smørgrav done: 3033fc9e2c3SDag-Erling Smørgrav ldns_pkt_free(qpkt); 3043fc9e2c3SDag-Erling Smørgrav 3053fc9e2c3SDag-Erling Smørgrav ldns_resolver_set_nameservers(res, ns); 3063fc9e2c3SDag-Erling Smørgrav ldns_resolver_set_rtt(res, rtt); 3073fc9e2c3SDag-Erling Smørgrav ldns_resolver_set_nameserver_count(res, nscnt); 3083fc9e2c3SDag-Erling Smørgrav return status; 3093fc9e2c3SDag-Erling Smørgrav } 3103fc9e2c3SDag-Erling Smørgrav 3113fc9e2c3SDag-Erling Smørgrav static void 3123fc9e2c3SDag-Erling Smørgrav ldns_pkt_filter_answer(ldns_pkt *pkt, ldns_rr_type type) { 3133fc9e2c3SDag-Erling Smørgrav int i, j, cnt; 3143fc9e2c3SDag-Erling Smørgrav ldns_rr_list *rrlist; 3153fc9e2c3SDag-Erling Smørgrav ldns_rr *rr; 3163fc9e2c3SDag-Erling Smørgrav ldns_rr_type rrtype; 3173fc9e2c3SDag-Erling Smørgrav 3183fc9e2c3SDag-Erling Smørgrav rrlist = ldns_pkt_answer(pkt); 3193fc9e2c3SDag-Erling Smørgrav cnt = ldns_rr_list_rr_count(rrlist); 3203fc9e2c3SDag-Erling Smørgrav for (i = j = 0; i < cnt; i++) { 3213fc9e2c3SDag-Erling Smørgrav rr = ldns_rr_list_rr(rrlist, i); 3223fc9e2c3SDag-Erling Smørgrav rrtype = ldns_rr_get_type(rr); 3233fc9e2c3SDag-Erling Smørgrav if (type == LDNS_RR_TYPE_ANY || 3243fc9e2c3SDag-Erling Smørgrav type == rrtype || 3253fc9e2c3SDag-Erling Smørgrav (type == LDNS_RR_TYPE_AXFR && 3263fc9e2c3SDag-Erling Smørgrav (rrtype == LDNS_RR_TYPE_A || 3273fc9e2c3SDag-Erling Smørgrav rrtype == LDNS_RR_TYPE_AAAA || 3283fc9e2c3SDag-Erling Smørgrav rrtype == LDNS_RR_TYPE_NS || 3293fc9e2c3SDag-Erling Smørgrav rrtype == LDNS_RR_TYPE_PTR))) 3303fc9e2c3SDag-Erling Smørgrav ldns_rr_list_set_rr(rrlist, rr, j++); 3313fc9e2c3SDag-Erling Smørgrav } 3323fc9e2c3SDag-Erling Smørgrav ldns_rr_list_set_rr_count(rrlist, j); 3333fc9e2c3SDag-Erling Smørgrav } 3343fc9e2c3SDag-Erling Smørgrav 3353fc9e2c3SDag-Erling Smørgrav /* Packet content printing. 3363fc9e2c3SDag-Erling Smørgrav */ 3373fc9e2c3SDag-Erling Smørgrav 3383fc9e2c3SDag-Erling Smørgrav static struct { 3393fc9e2c3SDag-Erling Smørgrav ldns_rr_type type; 3403fc9e2c3SDag-Erling Smørgrav const char *text; 3413fc9e2c3SDag-Erling Smørgrav } rr_types[] = { 3423fc9e2c3SDag-Erling Smørgrav {LDNS_RR_TYPE_A, "has address"}, 3433fc9e2c3SDag-Erling Smørgrav {LDNS_RR_TYPE_NS, "name server"}, 3443fc9e2c3SDag-Erling Smørgrav {LDNS_RR_TYPE_CNAME, "is an alias for"}, 3453fc9e2c3SDag-Erling Smørgrav {LDNS_RR_TYPE_WKS, "has well known services"}, 3463fc9e2c3SDag-Erling Smørgrav {LDNS_RR_TYPE_PTR, "domain name pointer"}, 3473fc9e2c3SDag-Erling Smørgrav {LDNS_RR_TYPE_HINFO, "host information"}, 3483fc9e2c3SDag-Erling Smørgrav {LDNS_RR_TYPE_MX, "mail is handled by"}, 3493fc9e2c3SDag-Erling Smørgrav {LDNS_RR_TYPE_TXT, "descriptive text"}, 3503fc9e2c3SDag-Erling Smørgrav {LDNS_RR_TYPE_X25, "x25 address"}, 3513fc9e2c3SDag-Erling Smørgrav {LDNS_RR_TYPE_ISDN, "ISDN address"}, 3523fc9e2c3SDag-Erling Smørgrav {LDNS_RR_TYPE_SIG, "has signature"}, 3533fc9e2c3SDag-Erling Smørgrav {LDNS_RR_TYPE_KEY, "has key"}, 3543fc9e2c3SDag-Erling Smørgrav {LDNS_RR_TYPE_AAAA, "has IPv6 address"}, 3553fc9e2c3SDag-Erling Smørgrav {LDNS_RR_TYPE_LOC, "location"}, 3563fc9e2c3SDag-Erling Smørgrav }; 3573fc9e2c3SDag-Erling Smørgrav 3583fc9e2c3SDag-Erling Smørgrav static void 3593fc9e2c3SDag-Erling Smørgrav print_opcode(ldns_pkt_opcode opcode) { 3603fc9e2c3SDag-Erling Smørgrav ldns_lookup_table *lt = ldns_lookup_by_id(ldns_opcodes, opcode); 3613fc9e2c3SDag-Erling Smørgrav 3623fc9e2c3SDag-Erling Smørgrav if (lt && lt->name) 3633fc9e2c3SDag-Erling Smørgrav printf("%s", lt->name); 3643fc9e2c3SDag-Erling Smørgrav else 3653fc9e2c3SDag-Erling Smørgrav printf("RESERVED%d", opcode); 3663fc9e2c3SDag-Erling Smørgrav } 3673fc9e2c3SDag-Erling Smørgrav 3683fc9e2c3SDag-Erling Smørgrav static void 3693fc9e2c3SDag-Erling Smørgrav print_rcode(uint8_t rcode) { 3703fc9e2c3SDag-Erling Smørgrav ldns_lookup_table *lt = ldns_lookup_by_id(ldns_rcodes, rcode); 3713fc9e2c3SDag-Erling Smørgrav 3723fc9e2c3SDag-Erling Smørgrav if (lt && lt->name) 3733fc9e2c3SDag-Erling Smørgrav printf("%s", lt->name); 3743fc9e2c3SDag-Erling Smørgrav else 3753fc9e2c3SDag-Erling Smørgrav printf("RESERVED%d", rcode); 3763fc9e2c3SDag-Erling Smørgrav } 3773fc9e2c3SDag-Erling Smørgrav 3783fc9e2c3SDag-Erling Smørgrav static int 3793fc9e2c3SDag-Erling Smørgrav print_rr_type(ldns_rr_type type) { 3803fc9e2c3SDag-Erling Smørgrav char *str; 3813fc9e2c3SDag-Erling Smørgrav int n; 3823fc9e2c3SDag-Erling Smørgrav 3833fc9e2c3SDag-Erling Smørgrav str = ldns_rr_type2str(type); 3843fc9e2c3SDag-Erling Smørgrav n = printf("%s", str); 3853fc9e2c3SDag-Erling Smørgrav free(str); 3863fc9e2c3SDag-Erling Smørgrav return n; 3873fc9e2c3SDag-Erling Smørgrav } 3883fc9e2c3SDag-Erling Smørgrav 3893fc9e2c3SDag-Erling Smørgrav static int 3903fc9e2c3SDag-Erling Smørgrav print_rr_class(ldns_rr_class cls) { 3913fc9e2c3SDag-Erling Smørgrav char *str; 3923fc9e2c3SDag-Erling Smørgrav int n; 3933fc9e2c3SDag-Erling Smørgrav 3943fc9e2c3SDag-Erling Smørgrav str = ldns_rr_class2str(cls); 3953fc9e2c3SDag-Erling Smørgrav n = printf("%s", str); 3963fc9e2c3SDag-Erling Smørgrav free(str); 3973fc9e2c3SDag-Erling Smørgrav return n; 3983fc9e2c3SDag-Erling Smørgrav } 3993fc9e2c3SDag-Erling Smørgrav 4003fc9e2c3SDag-Erling Smørgrav static int 4013fc9e2c3SDag-Erling Smørgrav print_rdf(ldns_rdf *rdf) { 4023fc9e2c3SDag-Erling Smørgrav char *str; 4033fc9e2c3SDag-Erling Smørgrav int n; 4043fc9e2c3SDag-Erling Smørgrav 4053fc9e2c3SDag-Erling Smørgrav str = ldns_rdf2str(rdf); 4063fc9e2c3SDag-Erling Smørgrav n = printf("%s", str); 4073fc9e2c3SDag-Erling Smørgrav free(str); 4083fc9e2c3SDag-Erling Smørgrav return n; 4093fc9e2c3SDag-Erling Smørgrav } 4103fc9e2c3SDag-Erling Smørgrav 4113fc9e2c3SDag-Erling Smørgrav static int 4123fc9e2c3SDag-Erling Smørgrav print_rdf_nodot(ldns_rdf *rdf) { 4133fc9e2c3SDag-Erling Smørgrav char *str; 4143fc9e2c3SDag-Erling Smørgrav int len, n; 4153fc9e2c3SDag-Erling Smørgrav 4163fc9e2c3SDag-Erling Smørgrav str = ldns_rdf2str(rdf); 4173fc9e2c3SDag-Erling Smørgrav len = strlen(str); 4183fc9e2c3SDag-Erling Smørgrav n = printf("%.*s", str[len-1] == '.' ? len-1 : len, str); 4193fc9e2c3SDag-Erling Smørgrav free(str); 4203fc9e2c3SDag-Erling Smørgrav return n; 4213fc9e2c3SDag-Erling Smørgrav } 4223fc9e2c3SDag-Erling Smørgrav 4233fc9e2c3SDag-Erling Smørgrav static int 4243fc9e2c3SDag-Erling Smørgrav print_padding(int fromcol, int tocol) { 4253fc9e2c3SDag-Erling Smørgrav int col = fromcol, nextcol = fromcol + 8 - fromcol%8; 4263fc9e2c3SDag-Erling Smørgrav 4273fc9e2c3SDag-Erling Smørgrav if (fromcol + 1 > tocol) tocol = fromcol + 1; 4283fc9e2c3SDag-Erling Smørgrav for (; nextcol <= tocol; col = nextcol, nextcol += 8) 4293fc9e2c3SDag-Erling Smørgrav printf("\t"); 4303fc9e2c3SDag-Erling Smørgrav for (; col < tocol; col++) 4313fc9e2c3SDag-Erling Smørgrav printf(" "); 4323fc9e2c3SDag-Erling Smørgrav return col - fromcol; 4333fc9e2c3SDag-Erling Smørgrav } 4343fc9e2c3SDag-Erling Smørgrav 4353fc9e2c3SDag-Erling Smørgrav static void 4363fc9e2c3SDag-Erling Smørgrav print_rr_verbose(ldns_rr *rr) { 4373fc9e2c3SDag-Erling Smørgrav bool isq = ldns_rr_is_question(rr); 4383fc9e2c3SDag-Erling Smørgrav int rdcnt = ldns_rr_rd_count(rr); 4393fc9e2c3SDag-Erling Smørgrav int i, n; 4403fc9e2c3SDag-Erling Smørgrav 4413fc9e2c3SDag-Erling Smørgrav /* bind9-host does not count the initial ';' here */ 4423fc9e2c3SDag-Erling Smørgrav n = isq ? printf(";") : 0; 4433fc9e2c3SDag-Erling Smørgrav n = print_rdf(ldns_rr_owner(rr)); 4443fc9e2c3SDag-Erling Smørgrav if (!isq) { 4453fc9e2c3SDag-Erling Smørgrav n += print_padding(n, 24); 4463fc9e2c3SDag-Erling Smørgrav n += printf("%d", ldns_rr_ttl(rr)); 4473fc9e2c3SDag-Erling Smørgrav } 4483fc9e2c3SDag-Erling Smørgrav n += print_padding(n, 32); 4493fc9e2c3SDag-Erling Smørgrav n += print_rr_class(ldns_rr_get_class(rr)); 4503fc9e2c3SDag-Erling Smørgrav n += print_padding(n, 40); 4513fc9e2c3SDag-Erling Smørgrav n += print_rr_type(ldns_rr_get_type(rr)); 4523fc9e2c3SDag-Erling Smørgrav for (i = 0; i < rdcnt; i++) { 4533fc9e2c3SDag-Erling Smørgrav if (i == 0) print_padding(n, 48); 4543fc9e2c3SDag-Erling Smørgrav else printf(" "); 4553fc9e2c3SDag-Erling Smørgrav print_rdf(ldns_rr_rdf(rr, i)); 4563fc9e2c3SDag-Erling Smørgrav } 4573fc9e2c3SDag-Erling Smørgrav printf("\n"); 4583fc9e2c3SDag-Erling Smørgrav } 4593fc9e2c3SDag-Erling Smørgrav 4603fc9e2c3SDag-Erling Smørgrav static void 4613fc9e2c3SDag-Erling Smørgrav print_pkt_section_verbose(const char *name, ldns_rr_list *rrlist) { 4623fc9e2c3SDag-Erling Smørgrav int i, cnt = ldns_rr_list_rr_count(rrlist); 4633fc9e2c3SDag-Erling Smørgrav 4643fc9e2c3SDag-Erling Smørgrav if (cnt == 0) 4653fc9e2c3SDag-Erling Smørgrav return; 4663fc9e2c3SDag-Erling Smørgrav printf(";; %s SECTION:\n", name); 4673fc9e2c3SDag-Erling Smørgrav for (i = 0; i < cnt; i++) 4683fc9e2c3SDag-Erling Smørgrav print_rr_verbose(ldns_rr_list_rr(rrlist, i)); 4693fc9e2c3SDag-Erling Smørgrav printf("\n"); 4703fc9e2c3SDag-Erling Smørgrav } 4713fc9e2c3SDag-Erling Smørgrav 4723fc9e2c3SDag-Erling Smørgrav static void 4733fc9e2c3SDag-Erling Smørgrav print_pkt_verbose(ldns_pkt *pkt) { 4743fc9e2c3SDag-Erling Smørgrav int got_flags = 0; 4753fc9e2c3SDag-Erling Smørgrav 4763fc9e2c3SDag-Erling Smørgrav printf(";; ->>HEADER<<- opcode: "); 4773fc9e2c3SDag-Erling Smørgrav print_opcode(ldns_pkt_get_opcode(pkt)); 4783fc9e2c3SDag-Erling Smørgrav printf(", status: "); 4793fc9e2c3SDag-Erling Smørgrav print_rcode(ldns_pkt_get_rcode(pkt)); 4803fc9e2c3SDag-Erling Smørgrav printf(", id: %u\n", ldns_pkt_id(pkt)); 4813fc9e2c3SDag-Erling Smørgrav printf(";; flags:"); 4823fc9e2c3SDag-Erling Smørgrav if (ldns_pkt_qr(pkt)) printf(" qr"), got_flags = 1; 4833fc9e2c3SDag-Erling Smørgrav if (ldns_pkt_aa(pkt)) printf(" aa"), got_flags = 1; 4843fc9e2c3SDag-Erling Smørgrav if (ldns_pkt_tc(pkt)) printf(" tc"), got_flags = 1; 4853fc9e2c3SDag-Erling Smørgrav if (ldns_pkt_rd(pkt)) printf(" rd"), got_flags = 1; 4863fc9e2c3SDag-Erling Smørgrav if (ldns_pkt_ra(pkt)) printf(" ra"), got_flags = 1; 4873fc9e2c3SDag-Erling Smørgrav if (ldns_pkt_ad(pkt)) printf(" ad"), got_flags = 1; 4883fc9e2c3SDag-Erling Smørgrav if (ldns_pkt_cd(pkt)) printf(" cd"), got_flags = 1; 4893fc9e2c3SDag-Erling Smørgrav if (!got_flags) printf(" "); 4903fc9e2c3SDag-Erling Smørgrav printf("; QUERY: %u, ANSWER: %u, AUTHORITY: %u, ADDITIONAL: %u\n", 4913fc9e2c3SDag-Erling Smørgrav ldns_pkt_qdcount(pkt), ldns_pkt_ancount(pkt), 4923fc9e2c3SDag-Erling Smørgrav ldns_pkt_nscount(pkt), ldns_pkt_arcount(pkt)); 4933fc9e2c3SDag-Erling Smørgrav if (ldns_pkt_edns(pkt)) 4943fc9e2c3SDag-Erling Smørgrav printf(";; EDNS: version: %u, udp=%u\n", 4953fc9e2c3SDag-Erling Smørgrav ldns_pkt_edns_version(pkt), ldns_pkt_edns_udp_size(pkt)); 4963fc9e2c3SDag-Erling Smørgrav printf("\n"); 4973fc9e2c3SDag-Erling Smørgrav print_pkt_section_verbose("QUESTION", ldns_pkt_question(pkt)); 4983fc9e2c3SDag-Erling Smørgrav print_pkt_section_verbose("ANSWER", ldns_pkt_answer(pkt)); 4993fc9e2c3SDag-Erling Smørgrav print_pkt_section_verbose("AUTHORITY", ldns_pkt_authority(pkt)); 5003fc9e2c3SDag-Erling Smørgrav print_pkt_section_verbose("ADDITIONAL", ldns_pkt_additional(pkt)); 5013fc9e2c3SDag-Erling Smørgrav } 5023fc9e2c3SDag-Erling Smørgrav 5033fc9e2c3SDag-Erling Smørgrav static void 5043fc9e2c3SDag-Erling Smørgrav print_rr_short(ldns_rr *rr) { 5053fc9e2c3SDag-Erling Smørgrav ldns_rr_type type = ldns_rr_get_type(rr); 5063fc9e2c3SDag-Erling Smørgrav size_t i, rdcnt = ldns_rr_rd_count(rr); 5073fc9e2c3SDag-Erling Smørgrav 5083fc9e2c3SDag-Erling Smørgrav print_rdf_nodot(ldns_rr_owner(rr)); 5093fc9e2c3SDag-Erling Smørgrav printf(" "); 5103fc9e2c3SDag-Erling Smørgrav for (i = 0; i < countof(rr_types); i++) { 5113fc9e2c3SDag-Erling Smørgrav if (rr_types[i].type == type) { 5123fc9e2c3SDag-Erling Smørgrav printf("%s", rr_types[i].text); 5133fc9e2c3SDag-Erling Smørgrav goto found; 5143fc9e2c3SDag-Erling Smørgrav } 5153fc9e2c3SDag-Erling Smørgrav } 5163fc9e2c3SDag-Erling Smørgrav 5173fc9e2c3SDag-Erling Smørgrav printf("has "); 5183fc9e2c3SDag-Erling Smørgrav print_rr_type(type); 5193fc9e2c3SDag-Erling Smørgrav printf(" record"); 5203fc9e2c3SDag-Erling Smørgrav 5213fc9e2c3SDag-Erling Smørgrav found: 5223fc9e2c3SDag-Erling Smørgrav for (i = 0; i < rdcnt; i++) { 5233fc9e2c3SDag-Erling Smørgrav printf(" "); 5243fc9e2c3SDag-Erling Smørgrav print_rdf(ldns_rr_rdf(rr, i)); 5253fc9e2c3SDag-Erling Smørgrav } 5263fc9e2c3SDag-Erling Smørgrav printf("\n"); 5273fc9e2c3SDag-Erling Smørgrav } 5283fc9e2c3SDag-Erling Smørgrav 5293fc9e2c3SDag-Erling Smørgrav static void 5303fc9e2c3SDag-Erling Smørgrav print_pkt_short(ldns_pkt *pkt, bool print_rr_server) { 5313fc9e2c3SDag-Erling Smørgrav ldns_rr_list *rrlist = ldns_pkt_answer(pkt); 5323fc9e2c3SDag-Erling Smørgrav size_t i; 5333fc9e2c3SDag-Erling Smørgrav 5343fc9e2c3SDag-Erling Smørgrav for (i = 0; i < ldns_rr_list_rr_count(rrlist); i++) { 5353fc9e2c3SDag-Erling Smørgrav if (print_rr_server) { 5363fc9e2c3SDag-Erling Smørgrav printf("Nameserver "); 5373fc9e2c3SDag-Erling Smørgrav print_rdf(ldns_pkt_answerfrom(pkt)); 5383fc9e2c3SDag-Erling Smørgrav printf(":\n\t"); 5393fc9e2c3SDag-Erling Smørgrav } 5403fc9e2c3SDag-Erling Smørgrav print_rr_short(ldns_rr_list_rr(rrlist, i)); 5413fc9e2c3SDag-Erling Smørgrav } 5423fc9e2c3SDag-Erling Smørgrav } 5433fc9e2c3SDag-Erling Smørgrav 5443fc9e2c3SDag-Erling Smørgrav static void 5453fc9e2c3SDag-Erling Smørgrav print_received_line(ldns_resolver *res, ldns_pkt *pkt) { 5463fc9e2c3SDag-Erling Smørgrav char *from = ldns_rdf2str(ldns_pkt_answerfrom(pkt)); 5473fc9e2c3SDag-Erling Smørgrav 5483fc9e2c3SDag-Erling Smørgrav printf("Received %zu bytes from %s#%d in %d ms\n", 5493fc9e2c3SDag-Erling Smørgrav ldns_pkt_size(pkt), from, ldns_resolver_port(res), 5503fc9e2c3SDag-Erling Smørgrav ldns_pkt_querytime(pkt)); 5513fc9e2c3SDag-Erling Smørgrav free(from); 5523fc9e2c3SDag-Erling Smørgrav } 5533fc9e2c3SDag-Erling Smørgrav 5543fc9e2c3SDag-Erling Smørgrav /* Main program. 5553fc9e2c3SDag-Erling Smørgrav * 5563fc9e2c3SDag-Erling Smørgrav * Note that no memory is freed below this line by intention. 5573fc9e2c3SDag-Erling Smørgrav */ 5583fc9e2c3SDag-Erling Smørgrav 5593fc9e2c3SDag-Erling Smørgrav #define DEFAULT_TCP_TIMEOUT 10 5603fc9e2c3SDag-Erling Smørgrav #define DEFAULT_UDP_TIMEOUT 5 5613fc9e2c3SDag-Erling Smørgrav 562*3f68b24eSDag-Erling Smørgrav enum operation_mode { M_AXFR, M_IXFR, M_DEFAULT_Q, M_SINGLE_Q, M_SOA }; 5633fc9e2c3SDag-Erling Smørgrav 5643fc9e2c3SDag-Erling Smørgrav static enum operation_mode o_mode = M_DEFAULT_Q; 5653fc9e2c3SDag-Erling Smørgrav static bool o_ignore_servfail = true; 5663fc9e2c3SDag-Erling Smørgrav static bool o_ip6_int = false; 5673fc9e2c3SDag-Erling Smørgrav static bool o_print_pkt_server = false; 5683fc9e2c3SDag-Erling Smørgrav static bool o_print_rr_server = false; 5693fc9e2c3SDag-Erling Smørgrav static bool o_recursive = true; 5703fc9e2c3SDag-Erling Smørgrav static bool o_tcp = false; 5713fc9e2c3SDag-Erling Smørgrav static bool o_verbose = false; 5723fc9e2c3SDag-Erling Smørgrav static char *o_name = NULL; 5733fc9e2c3SDag-Erling Smørgrav static char *o_server = NULL; 5743fc9e2c3SDag-Erling Smørgrav static int o_ipversion = LDNS_RESOLV_INETANY; 5753fc9e2c3SDag-Erling Smørgrav static int o_ndots = 1; 5763fc9e2c3SDag-Erling Smørgrav static int o_retries = 1; 5773fc9e2c3SDag-Erling Smørgrav static ldns_rr_class o_rrclass = LDNS_RR_CLASS_IN; 578*3f68b24eSDag-Erling Smørgrav static ldns_rr_type o_rrtype = (ldns_rr_type)-1; 5793fc9e2c3SDag-Erling Smørgrav static time_t o_timeout = 0; 5803fc9e2c3SDag-Erling Smørgrav static uint32_t o_ixfr_serial = 0; 5813fc9e2c3SDag-Erling Smørgrav 5823fc9e2c3SDag-Erling Smørgrav static void 5833fc9e2c3SDag-Erling Smørgrav usage(void) { 584*3f68b24eSDag-Erling Smørgrav fprintf(stderr, 585*3f68b24eSDag-Erling Smørgrav "Usage: %s [-aCdilrsTvw46] [-c class] [-N ndots] [-R number]\n" 586*3f68b24eSDag-Erling Smørgrav " %*c [-t type] [-W wait] name [server]\n" 5873fc9e2c3SDag-Erling Smørgrav "\t-a same as -v -t ANY\n" 5883fc9e2c3SDag-Erling Smørgrav "\t-C query SOA records from all authoritative name servers\n" 5893fc9e2c3SDag-Erling Smørgrav "\t-c use this query class (IN, CH, HS, etc)\n" 5903fc9e2c3SDag-Erling Smørgrav "\t-d produce verbose output, same as -v\n" 5913fc9e2c3SDag-Erling Smørgrav "\t-i use IP6.INT for IPv6 reverse lookups\n" 5923fc9e2c3SDag-Erling Smørgrav "\t-l list records in a zone via AXFR\n" 5933fc9e2c3SDag-Erling Smørgrav "\t-N consider names with at least this many dots as absolute\n" 5943fc9e2c3SDag-Erling Smørgrav "\t-R retry UDP queries this many times\n" 5953fc9e2c3SDag-Erling Smørgrav "\t-r disable recursive query\n" 5963fc9e2c3SDag-Erling Smørgrav "\t-s do not ignore SERVFAIL responses\n" 5973fc9e2c3SDag-Erling Smørgrav "\t-T send query via TCP\n" 5983fc9e2c3SDag-Erling Smørgrav "\t-t use this query type (A, AAAA, MX, etc)\n" 5993fc9e2c3SDag-Erling Smørgrav "\t-v produce verbose output\n" 6003fc9e2c3SDag-Erling Smørgrav "\t-w wait forever for a server reply\n" 6013fc9e2c3SDag-Erling Smørgrav "\t-W wait this many seconds for a reply\n" 6023fc9e2c3SDag-Erling Smørgrav "\t-4 use IPv4 only\n" 6033fc9e2c3SDag-Erling Smørgrav "\t-6 use IPv6 only\n", 604*3f68b24eSDag-Erling Smørgrav progname, (int)strlen(progname), ' '); 6053fc9e2c3SDag-Erling Smørgrav exit(1); 6063fc9e2c3SDag-Erling Smørgrav } 6073fc9e2c3SDag-Erling Smørgrav 6083fc9e2c3SDag-Erling Smørgrav static void 6093fc9e2c3SDag-Erling Smørgrav parse_args(int argc, char *argv[]) { 6103fc9e2c3SDag-Erling Smørgrav int ch; 6113fc9e2c3SDag-Erling Smørgrav 6123fc9e2c3SDag-Erling Smørgrav progname = argv[0]; 6133fc9e2c3SDag-Erling Smørgrav while ((ch = getopt(argc, argv, "aCdilrsTvw46c:N:R:t:W:")) != -1) { 6143fc9e2c3SDag-Erling Smørgrav switch (ch) { 6153fc9e2c3SDag-Erling Smørgrav case 'a': 6163fc9e2c3SDag-Erling Smørgrav if (o_mode != M_AXFR) 6173fc9e2c3SDag-Erling Smørgrav o_mode = M_SINGLE_Q; 6183fc9e2c3SDag-Erling Smørgrav o_rrtype = LDNS_RR_TYPE_ANY; 6193fc9e2c3SDag-Erling Smørgrav o_verbose = true; 6203fc9e2c3SDag-Erling Smørgrav break; 6213fc9e2c3SDag-Erling Smørgrav case 'C': 6223fc9e2c3SDag-Erling Smørgrav o_mode = M_SOA; 6233fc9e2c3SDag-Erling Smørgrav o_print_rr_server = true; 6243fc9e2c3SDag-Erling Smørgrav o_rrclass = LDNS_RR_CLASS_IN; 6253fc9e2c3SDag-Erling Smørgrav o_rrtype = LDNS_RR_TYPE_NS; 6263fc9e2c3SDag-Erling Smørgrav break; 6273fc9e2c3SDag-Erling Smørgrav case 'c': 6283fc9e2c3SDag-Erling Smørgrav /* bind9-host sets o_mode to M_SINGLE_Q here */ 6293fc9e2c3SDag-Erling Smørgrav o_rrclass = ldns_get_rr_class_by_name(optarg); 6303fc9e2c3SDag-Erling Smørgrav if (o_rrclass <= 0) 6313fc9e2c3SDag-Erling Smørgrav die(2, "invalid class: %s\n", optarg); 6323fc9e2c3SDag-Erling Smørgrav break; 6333fc9e2c3SDag-Erling Smørgrav case 'd': o_verbose = true; break; 6343fc9e2c3SDag-Erling Smørgrav case 'i': o_ip6_int = true; break; 6353fc9e2c3SDag-Erling Smørgrav case 'l': 6363fc9e2c3SDag-Erling Smørgrav o_mode = M_AXFR; 637*3f68b24eSDag-Erling Smørgrav if (o_rrtype == (ldns_rr_type)-1) 6383fc9e2c3SDag-Erling Smørgrav o_rrtype = LDNS_RR_TYPE_AXFR; 6393fc9e2c3SDag-Erling Smørgrav o_tcp = true; 6403fc9e2c3SDag-Erling Smørgrav break; 6413fc9e2c3SDag-Erling Smørgrav case 'N': 6423fc9e2c3SDag-Erling Smørgrav o_ndots = atoi(optarg); 6433fc9e2c3SDag-Erling Smørgrav if (o_ndots < 0) o_ndots = 0; 6443fc9e2c3SDag-Erling Smørgrav break; 6453fc9e2c3SDag-Erling Smørgrav case 'n': 6463fc9e2c3SDag-Erling Smørgrav /* bind9-host accepts and ignores this option */ 6473fc9e2c3SDag-Erling Smørgrav break; 6483fc9e2c3SDag-Erling Smørgrav case 'r': o_recursive = 0; break; 6493fc9e2c3SDag-Erling Smørgrav case 'R': 6503fc9e2c3SDag-Erling Smørgrav o_retries = atoi(optarg); 6513fc9e2c3SDag-Erling Smørgrav if (o_retries <= 0) o_retries = 1; 6523fc9e2c3SDag-Erling Smørgrav if (o_retries > 255) o_retries = 255; 6533fc9e2c3SDag-Erling Smørgrav break; 6543fc9e2c3SDag-Erling Smørgrav case 's': o_ignore_servfail = false; break; 6553fc9e2c3SDag-Erling Smørgrav case 'T': o_tcp = true; break; 6563fc9e2c3SDag-Erling Smørgrav case 't': 6573fc9e2c3SDag-Erling Smørgrav if (o_mode != M_AXFR) 6583fc9e2c3SDag-Erling Smørgrav o_mode = M_SINGLE_Q; 6593fc9e2c3SDag-Erling Smørgrav if (strncasecmp(optarg, "ixfr=", 5) == 0) { 6603fc9e2c3SDag-Erling Smørgrav o_rrtype = LDNS_RR_TYPE_IXFR; 6613fc9e2c3SDag-Erling Smørgrav o_ixfr_serial = atol(optarg + 5); 6623fc9e2c3SDag-Erling Smørgrav } else { 6633fc9e2c3SDag-Erling Smørgrav o_rrtype = ldns_get_rr_type_by_name(optarg); 6643fc9e2c3SDag-Erling Smørgrav if (o_rrtype <= 0) 6653fc9e2c3SDag-Erling Smørgrav die(2, "invalid type: %s\n", optarg); 6663fc9e2c3SDag-Erling Smørgrav } 6673fc9e2c3SDag-Erling Smørgrav if (o_rrtype == LDNS_RR_TYPE_AXFR) { 6683fc9e2c3SDag-Erling Smørgrav o_mode = M_AXFR; 6693fc9e2c3SDag-Erling Smørgrav o_rrtype = LDNS_RR_TYPE_ANY; 6703fc9e2c3SDag-Erling Smørgrav o_verbose = true; 6713fc9e2c3SDag-Erling Smørgrav } 672*3f68b24eSDag-Erling Smørgrav if (o_rrtype == LDNS_RR_TYPE_IXFR) { 673*3f68b24eSDag-Erling Smørgrav o_mode = M_IXFR; 674*3f68b24eSDag-Erling Smørgrav o_rrtype = LDNS_RR_TYPE_ANY; 675*3f68b24eSDag-Erling Smørgrav } 6763fc9e2c3SDag-Erling Smørgrav break; 6773fc9e2c3SDag-Erling Smørgrav case 'v': o_verbose = true; break; 6783fc9e2c3SDag-Erling Smørgrav case 'w': 6793fc9e2c3SDag-Erling Smørgrav o_timeout = (time_t)INT_MAX; 6803fc9e2c3SDag-Erling Smørgrav break; 6813fc9e2c3SDag-Erling Smørgrav case 'W': 6823fc9e2c3SDag-Erling Smørgrav o_timeout = atol(optarg); 6833fc9e2c3SDag-Erling Smørgrav if (o_timeout <= 0) o_timeout = 1; 6843fc9e2c3SDag-Erling Smørgrav break; 6853fc9e2c3SDag-Erling Smørgrav case '4': o_ipversion = LDNS_RESOLV_INET; break; 6863fc9e2c3SDag-Erling Smørgrav case '6': o_ipversion = LDNS_RESOLV_INET6; break; 6873fc9e2c3SDag-Erling Smørgrav default: 6883fc9e2c3SDag-Erling Smørgrav usage(); 6893fc9e2c3SDag-Erling Smørgrav } 6903fc9e2c3SDag-Erling Smørgrav } 6913fc9e2c3SDag-Erling Smørgrav argc -= optind; 6923fc9e2c3SDag-Erling Smørgrav argv += optind; 6933fc9e2c3SDag-Erling Smørgrav /* bind9-host ignores arguments after the 2-nd one */ 6943fc9e2c3SDag-Erling Smørgrav if (argc < 1) 6953fc9e2c3SDag-Erling Smørgrav usage(); 6963fc9e2c3SDag-Erling Smørgrav o_name = argv[0]; 6973fc9e2c3SDag-Erling Smørgrav if (argc > 1) { 6983fc9e2c3SDag-Erling Smørgrav o_server = argv[1]; 6993fc9e2c3SDag-Erling Smørgrav o_print_pkt_server = true; 7003fc9e2c3SDag-Erling Smørgrav } 701*3f68b24eSDag-Erling Smørgrav if (o_rrtype == (ldns_rr_type)-1) 702*3f68b24eSDag-Erling Smørgrav o_rrtype = LDNS_RR_TYPE_A; 7033fc9e2c3SDag-Erling Smørgrav } 7043fc9e2c3SDag-Erling Smørgrav 7053fc9e2c3SDag-Erling Smørgrav static ldns_rdf* 7063fc9e2c3SDag-Erling Smørgrav safe_str2rdf_dname(const char *name) { 7073fc9e2c3SDag-Erling Smørgrav ldns_rdf *dname; 7083fc9e2c3SDag-Erling Smørgrav ldns_status status; 7093fc9e2c3SDag-Erling Smørgrav 7103fc9e2c3SDag-Erling Smørgrav if ((status = ldns_str2rdf_dname(&dname, name)) != LDNS_STATUS_OK) { 7113fc9e2c3SDag-Erling Smørgrav die(1, "'%s' is not a legal name (%s)", 7123fc9e2c3SDag-Erling Smørgrav name, ldns_get_errorstr_by_id(status)); 7133fc9e2c3SDag-Erling Smørgrav } 7143fc9e2c3SDag-Erling Smørgrav return dname; 7153fc9e2c3SDag-Erling Smørgrav } 7163fc9e2c3SDag-Erling Smørgrav 7173fc9e2c3SDag-Erling Smørgrav static ldns_rdf* 7183fc9e2c3SDag-Erling Smørgrav safe_dname_cat_clone(const ldns_rdf *rd1, const ldns_rdf *rd2) { 7193fc9e2c3SDag-Erling Smørgrav ldns_rdf *result = ldns_dname_cat_clone(rd1, rd2); 7203fc9e2c3SDag-Erling Smørgrav 7213fc9e2c3SDag-Erling Smørgrav if (!result) 7223fc9e2c3SDag-Erling Smørgrav die(1, "not enought memory for a domain name"); 7233fc9e2c3SDag-Erling Smørgrav /* Why doesn't ldns_dname_cat_clone check this condition? */ 7243fc9e2c3SDag-Erling Smørgrav if (ldns_rdf_size(result) > LDNS_MAX_DOMAINLEN) 7253fc9e2c3SDag-Erling Smørgrav die(1, "'%s' is not a legal name (%s)\n", ldns_rdf2str(result), 7263fc9e2c3SDag-Erling Smørgrav ldns_get_errorstr_by_id(LDNS_STATUS_DOMAINNAME_OVERFLOW)); 7273fc9e2c3SDag-Erling Smørgrav return result; 7283fc9e2c3SDag-Erling Smørgrav } 7293fc9e2c3SDag-Erling Smørgrav 7303fc9e2c3SDag-Erling Smørgrav static bool 731*3f68b24eSDag-Erling Smørgrav query(ldns_resolver *res, ldns_rdf *domain, ldns_pkt **pkt, bool close_tcp) { 7323fc9e2c3SDag-Erling Smørgrav ldns_status status; 7333fc9e2c3SDag-Erling Smørgrav ldns_pkt_rcode rcode; 7343fc9e2c3SDag-Erling Smørgrav int i, cnt; 7353fc9e2c3SDag-Erling Smørgrav 7363fc9e2c3SDag-Erling Smørgrav if (o_verbose) { 7373fc9e2c3SDag-Erling Smørgrav printf("Trying \""); 7383fc9e2c3SDag-Erling Smørgrav print_rdf_nodot(domain); 7393fc9e2c3SDag-Erling Smørgrav printf("\"\n"); 7403fc9e2c3SDag-Erling Smørgrav } 7413fc9e2c3SDag-Erling Smørgrav for (cnt = ldns_resolver_nameserver_count(res), i = 0; i < cnt; i++) { 7423fc9e2c3SDag-Erling Smørgrav status = ldns_resolver_send_to(pkt, res, domain, o_rrtype, 743*3f68b24eSDag-Erling Smørgrav o_rrclass, o_recursive ? LDNS_RD : 0, o_ixfr_serial, i, 744*3f68b24eSDag-Erling Smørgrav close_tcp); 7453fc9e2c3SDag-Erling Smørgrav if (status != LDNS_STATUS_OK) { 7463fc9e2c3SDag-Erling Smørgrav *pkt = NULL; 7473fc9e2c3SDag-Erling Smørgrav continue; 7483fc9e2c3SDag-Erling Smørgrav } 7493fc9e2c3SDag-Erling Smørgrav if (ldns_pkt_tc(*pkt) && !ldns_resolver_usevc(res)) { 7503fc9e2c3SDag-Erling Smørgrav if (o_verbose) 7513fc9e2c3SDag-Erling Smørgrav printf(";; Truncated, retrying in TCP mode.\n"); 7523fc9e2c3SDag-Erling Smørgrav ldns_resolver_set_usevc(res, true); 7533fc9e2c3SDag-Erling Smørgrav status = ldns_resolver_send_to(pkt, res, domain, o_rrtype, 754*3f68b24eSDag-Erling Smørgrav o_rrclass, o_recursive ? LDNS_RD : 0, o_ixfr_serial, i, 755*3f68b24eSDag-Erling Smørgrav close_tcp); 7563fc9e2c3SDag-Erling Smørgrav ldns_resolver_set_usevc(res, false); 7573fc9e2c3SDag-Erling Smørgrav if (status != LDNS_STATUS_OK) 7583fc9e2c3SDag-Erling Smørgrav continue; 7593fc9e2c3SDag-Erling Smørgrav } 7603fc9e2c3SDag-Erling Smørgrav rcode = ldns_pkt_get_rcode(*pkt); 7613fc9e2c3SDag-Erling Smørgrav if (o_ignore_servfail && rcode == LDNS_RCODE_SERVFAIL && cnt > 1) 7623fc9e2c3SDag-Erling Smørgrav continue; 7633fc9e2c3SDag-Erling Smørgrav return rcode == LDNS_RCODE_NOERROR; 7643fc9e2c3SDag-Erling Smørgrav } 7653fc9e2c3SDag-Erling Smørgrav if (*pkt == NULL) { 7663fc9e2c3SDag-Erling Smørgrav printf(";; connection timed out; no servers could be reached\n"); 7673fc9e2c3SDag-Erling Smørgrav exit(1); 7683fc9e2c3SDag-Erling Smørgrav } 7693fc9e2c3SDag-Erling Smørgrav return false; 7703fc9e2c3SDag-Erling Smørgrav } 7713fc9e2c3SDag-Erling Smørgrav 7723fc9e2c3SDag-Erling Smørgrav static ldns_rdf * 773*3f68b24eSDag-Erling Smørgrav search(ldns_resolver *res, ldns_rdf *domain, ldns_pkt **pkt, 774*3f68b24eSDag-Erling Smørgrav bool absolute, bool close_tcp) { 7753fc9e2c3SDag-Erling Smørgrav ldns_rdf *dname, **searchlist; 7763fc9e2c3SDag-Erling Smørgrav int i, n; 7773fc9e2c3SDag-Erling Smørgrav 778*3f68b24eSDag-Erling Smørgrav if (absolute && query(res, domain, pkt, close_tcp)) 7793fc9e2c3SDag-Erling Smørgrav return domain; 7803fc9e2c3SDag-Erling Smørgrav 7813fc9e2c3SDag-Erling Smørgrav if ((dname = ldns_resolver_domain(res)) != NULL) { 7823fc9e2c3SDag-Erling Smørgrav dname = safe_dname_cat_clone(domain, dname); 783*3f68b24eSDag-Erling Smørgrav if (query(res, dname, pkt, close_tcp)) 7843fc9e2c3SDag-Erling Smørgrav return dname; 7853fc9e2c3SDag-Erling Smørgrav } 7863fc9e2c3SDag-Erling Smørgrav 7873fc9e2c3SDag-Erling Smørgrav searchlist = ldns_resolver_searchlist(res); 7883fc9e2c3SDag-Erling Smørgrav n = ldns_resolver_searchlist_count(res); 7893fc9e2c3SDag-Erling Smørgrav for (i = 0; i < n; i++) { 7903fc9e2c3SDag-Erling Smørgrav dname = safe_dname_cat_clone(domain, searchlist[i]); 791*3f68b24eSDag-Erling Smørgrav if (query(res, dname, pkt, close_tcp)) 7923fc9e2c3SDag-Erling Smørgrav return dname; 7933fc9e2c3SDag-Erling Smørgrav } 7943fc9e2c3SDag-Erling Smørgrav 795*3f68b24eSDag-Erling Smørgrav if (!absolute && query(res, domain, pkt, close_tcp)) 7963fc9e2c3SDag-Erling Smørgrav return domain; 7973fc9e2c3SDag-Erling Smørgrav 7983fc9e2c3SDag-Erling Smørgrav return NULL; 7993fc9e2c3SDag-Erling Smørgrav } 8003fc9e2c3SDag-Erling Smørgrav 8013fc9e2c3SDag-Erling Smørgrav static void 8023fc9e2c3SDag-Erling Smørgrav report(ldns_resolver *res, ldns_rdf *domain, ldns_pkt *pkt) { 8033fc9e2c3SDag-Erling Smørgrav ldns_pkt_rcode rcode; 8043fc9e2c3SDag-Erling Smørgrav 8053fc9e2c3SDag-Erling Smørgrav if (o_print_pkt_server) { 8063fc9e2c3SDag-Erling Smørgrav printf("Using domain server:\nName: %s\nAddress: ", o_server); 8073fc9e2c3SDag-Erling Smørgrav print_rdf(ldns_pkt_answerfrom(pkt)); 8083fc9e2c3SDag-Erling Smørgrav printf("#%d\nAliases: \n\n", ldns_resolver_port(res)); 8093fc9e2c3SDag-Erling Smørgrav o_print_pkt_server = false; 8103fc9e2c3SDag-Erling Smørgrav } 8113fc9e2c3SDag-Erling Smørgrav rcode = ldns_pkt_get_rcode(pkt); 8123fc9e2c3SDag-Erling Smørgrav if (rcode != LDNS_RCODE_NOERROR) { 8133fc9e2c3SDag-Erling Smørgrav printf("Host "); 8143fc9e2c3SDag-Erling Smørgrav print_rdf_nodot(domain); 8153fc9e2c3SDag-Erling Smørgrav printf(" not found: %d(", rcode); 8163fc9e2c3SDag-Erling Smørgrav print_rcode(rcode); 8173fc9e2c3SDag-Erling Smørgrav printf(")\n"); 8183fc9e2c3SDag-Erling Smørgrav } else { 8193fc9e2c3SDag-Erling Smørgrav if (o_verbose) { 8203fc9e2c3SDag-Erling Smørgrav print_pkt_verbose(pkt); 8213fc9e2c3SDag-Erling Smørgrav } else { 8223fc9e2c3SDag-Erling Smørgrav print_pkt_short(pkt, o_print_rr_server); 823*3f68b24eSDag-Erling Smørgrav if (o_mode == M_SINGLE_Q && 8243fc9e2c3SDag-Erling Smørgrav ldns_rr_list_rr_count(ldns_pkt_answer(pkt)) == 0) { 8253fc9e2c3SDag-Erling Smørgrav print_rdf_nodot(domain); 8263fc9e2c3SDag-Erling Smørgrav printf(" has no "); 8273fc9e2c3SDag-Erling Smørgrav print_rr_type(o_rrtype); 8283fc9e2c3SDag-Erling Smørgrav printf(" record\n"); 8293fc9e2c3SDag-Erling Smørgrav } 8303fc9e2c3SDag-Erling Smørgrav } 8313fc9e2c3SDag-Erling Smørgrav } 8323fc9e2c3SDag-Erling Smørgrav if (o_verbose) 8333fc9e2c3SDag-Erling Smørgrav print_received_line(res, pkt); 8343fc9e2c3SDag-Erling Smørgrav } 8353fc9e2c3SDag-Erling Smørgrav 8363fc9e2c3SDag-Erling Smørgrav static bool 8373fc9e2c3SDag-Erling Smørgrav doquery(ldns_resolver *res, ldns_rdf *domain) { 8383fc9e2c3SDag-Erling Smørgrav ldns_pkt *pkt; 8393fc9e2c3SDag-Erling Smørgrav bool q; 8403fc9e2c3SDag-Erling Smørgrav 841*3f68b24eSDag-Erling Smørgrav q = query(res, domain, &pkt, true); 8423fc9e2c3SDag-Erling Smørgrav report(res, domain, pkt); 8433fc9e2c3SDag-Erling Smørgrav return q; 8443fc9e2c3SDag-Erling Smørgrav } 8453fc9e2c3SDag-Erling Smørgrav 8463fc9e2c3SDag-Erling Smørgrav static bool 8473fc9e2c3SDag-Erling Smørgrav doquery_filtered(ldns_resolver *res, ldns_rdf *domain) { 8483fc9e2c3SDag-Erling Smørgrav ldns_pkt *pkt; 8493fc9e2c3SDag-Erling Smørgrav bool q; 8503fc9e2c3SDag-Erling Smørgrav 851*3f68b24eSDag-Erling Smørgrav q = query(res, domain, &pkt, true); 8523fc9e2c3SDag-Erling Smørgrav ldns_pkt_filter_answer(pkt, o_rrtype); 8533fc9e2c3SDag-Erling Smørgrav report(res, domain, pkt); 8543fc9e2c3SDag-Erling Smørgrav return q; 8553fc9e2c3SDag-Erling Smørgrav } 8563fc9e2c3SDag-Erling Smørgrav 8573fc9e2c3SDag-Erling Smørgrav static bool 8583fc9e2c3SDag-Erling Smørgrav dosearch(ldns_resolver *res, ldns_rdf *domain, bool absolute) { 8593fc9e2c3SDag-Erling Smørgrav ldns_pkt *pkt; 8603fc9e2c3SDag-Erling Smørgrav ldns_rdf *dname; 8613fc9e2c3SDag-Erling Smørgrav 862*3f68b24eSDag-Erling Smørgrav dname = search(res, domain, &pkt, absolute, true); 8633fc9e2c3SDag-Erling Smørgrav report(res, dname != NULL ? dname : domain, pkt); 8643fc9e2c3SDag-Erling Smørgrav return o_mode != M_DEFAULT_Q ? (dname != NULL) : 8653fc9e2c3SDag-Erling Smørgrav (dname != NULL) && 8663fc9e2c3SDag-Erling Smørgrav (o_rrtype = LDNS_RR_TYPE_AAAA, doquery_filtered(res, dname)) && 8673fc9e2c3SDag-Erling Smørgrav (o_rrtype = LDNS_RR_TYPE_MX, doquery_filtered(res, dname)); 8683fc9e2c3SDag-Erling Smørgrav } 8693fc9e2c3SDag-Erling Smørgrav 8703fc9e2c3SDag-Erling Smørgrav static bool 871*3f68b24eSDag-Erling Smørgrav dozonetransfer(ldns_resolver *res, ldns_rdf *domain, bool absolute) { 872*3f68b24eSDag-Erling Smørgrav ldns_pkt *pkt, *nextpkt; 8733fc9e2c3SDag-Erling Smørgrav ldns_rdf *dname; 8743fc9e2c3SDag-Erling Smørgrav ldns_rr_type rrtype; 875*3f68b24eSDag-Erling Smørgrav ldns_rr_list *rrl; 876*3f68b24eSDag-Erling Smørgrav int i, nsoa = 0; 8773fc9e2c3SDag-Erling Smørgrav 8783fc9e2c3SDag-Erling Smørgrav rrtype = o_rrtype; 879*3f68b24eSDag-Erling Smørgrav o_rrtype = (o_mode == M_AXFR) ? LDNS_RR_TYPE_AXFR : LDNS_RR_TYPE_IXFR; 880*3f68b24eSDag-Erling Smørgrav dname = search(res, domain, &pkt, absolute, false); 881*3f68b24eSDag-Erling Smørgrav 882*3f68b24eSDag-Erling Smørgrav for (;;) { 883*3f68b24eSDag-Erling Smørgrav rrl = ldns_pkt_answer(pkt); 884*3f68b24eSDag-Erling Smørgrav for (i = ldns_rr_list_rr_count(rrl) - 1; i >= 0; i--) { 885*3f68b24eSDag-Erling Smørgrav if (ldns_rr_get_type(ldns_rr_list_rr(rrl, i)) == LDNS_RR_TYPE_SOA) 886*3f68b24eSDag-Erling Smørgrav nsoa++; 887*3f68b24eSDag-Erling Smørgrav } 8883fc9e2c3SDag-Erling Smørgrav ldns_pkt_filter_answer(pkt, rrtype); 8893fc9e2c3SDag-Erling Smørgrav report(res, dname != NULL ? dname : domain, pkt); 890*3f68b24eSDag-Erling Smørgrav if ((dname == NULL) || 891*3f68b24eSDag-Erling Smørgrav (ldns_pkt_get_rcode(pkt) != LDNS_RCODE_NOERROR)) { 892*3f68b24eSDag-Erling Smørgrav printf("; Transfer failed.\n"); 893*3f68b24eSDag-Erling Smørgrav ldns_tcp_close(res); 894*3f68b24eSDag-Erling Smørgrav return false; 895*3f68b24eSDag-Erling Smørgrav } 896*3f68b24eSDag-Erling Smørgrav if (nsoa >= 2) { 897*3f68b24eSDag-Erling Smørgrav ldns_tcp_close(res); 898*3f68b24eSDag-Erling Smørgrav return true; 899*3f68b24eSDag-Erling Smørgrav } 900*3f68b24eSDag-Erling Smørgrav if (ldns_tcp_read(&nextpkt, res) != LDNS_STATUS_OK) { 901*3f68b24eSDag-Erling Smørgrav printf("; Transfer failed.\n"); 902*3f68b24eSDag-Erling Smørgrav return false; 903*3f68b24eSDag-Erling Smørgrav } 904*3f68b24eSDag-Erling Smørgrav ldns_pkt_set_answerfrom(nextpkt, 905*3f68b24eSDag-Erling Smørgrav ldns_rdf_clone(ldns_pkt_answerfrom(pkt))); 906*3f68b24eSDag-Erling Smørgrav ldns_pkt_free(pkt); 907*3f68b24eSDag-Erling Smørgrav pkt = nextpkt; 908*3f68b24eSDag-Erling Smørgrav } 9093fc9e2c3SDag-Erling Smørgrav } 9103fc9e2c3SDag-Erling Smørgrav 9113fc9e2c3SDag-Erling Smørgrav static bool 9123fc9e2c3SDag-Erling Smørgrav dosoa(ldns_resolver *res, ldns_rdf *domain, bool absolute) { 9133fc9e2c3SDag-Erling Smørgrav ldns_rr_list *answer, **nsaddrs; 9143fc9e2c3SDag-Erling Smørgrav ldns_rdf *dname, *addr; 9153fc9e2c3SDag-Erling Smørgrav ldns_pkt *pkt; 9163fc9e2c3SDag-Erling Smørgrav ldns_rr *rr; 9173fc9e2c3SDag-Erling Smørgrav size_t i, j, n, cnt; 9183fc9e2c3SDag-Erling Smørgrav 919*3f68b24eSDag-Erling Smørgrav if ((dname = search(res, domain, &pkt, absolute, true)) == NULL) 9203fc9e2c3SDag-Erling Smørgrav return false; 9213fc9e2c3SDag-Erling Smørgrav 9223fc9e2c3SDag-Erling Smørgrav answer = ldns_pkt_answer(pkt); 9233fc9e2c3SDag-Erling Smørgrav cnt = ldns_rr_list_rr_count(answer); 9243fc9e2c3SDag-Erling Smørgrav nsaddrs = alloca(cnt*sizeof(*nsaddrs)); 9253fc9e2c3SDag-Erling Smørgrav for (n = 0, i = 0; i < cnt; i++) 9263fc9e2c3SDag-Erling Smørgrav if ((addr = ldns_rr_ns_nsdname(ldns_rr_list_rr(answer, i))) != NULL) 9273fc9e2c3SDag-Erling Smørgrav nsaddrs[n++] = ldns_get_rr_list_addr_by_name(res, 9283fc9e2c3SDag-Erling Smørgrav addr, LDNS_RR_CLASS_IN, 0); 9293fc9e2c3SDag-Erling Smørgrav 9303fc9e2c3SDag-Erling Smørgrav o_print_pkt_server = false; 9313fc9e2c3SDag-Erling Smørgrav o_recursive = false; 9323fc9e2c3SDag-Erling Smørgrav o_rrtype = LDNS_RR_TYPE_SOA; 9333fc9e2c3SDag-Erling Smørgrav for (i = 0; i < n; i++) { 9343fc9e2c3SDag-Erling Smørgrav cnt = ldns_rr_list_rr_count(nsaddrs[i]); 9353fc9e2c3SDag-Erling Smørgrav for (j = 0; j < cnt; j++) { 9363fc9e2c3SDag-Erling Smørgrav ldns_resolver_remove_nameservers(res); 9373fc9e2c3SDag-Erling Smørgrav rr = ldns_rr_list_rr(nsaddrs[i], j); 9383fc9e2c3SDag-Erling Smørgrav if ((ldns_resolver_ip6(res) == LDNS_RESOLV_INET && 9393fc9e2c3SDag-Erling Smørgrav ldns_rr_get_type(rr) == LDNS_RR_TYPE_AAAA) || 9403fc9e2c3SDag-Erling Smørgrav (ldns_resolver_ip6(res) == LDNS_RESOLV_INET6 && 9413fc9e2c3SDag-Erling Smørgrav ldns_rr_get_type(rr) == LDNS_RR_TYPE_A)) 9423fc9e2c3SDag-Erling Smørgrav continue; 9433fc9e2c3SDag-Erling Smørgrav if (ldns_resolver_push_nameserver_rr(res, rr) == LDNS_STATUS_OK) 9443fc9e2c3SDag-Erling Smørgrav /* bind9-host queries for domain, not dname here */ 9453fc9e2c3SDag-Erling Smørgrav doquery(res, dname); 9463fc9e2c3SDag-Erling Smørgrav } 9473fc9e2c3SDag-Erling Smørgrav } 9483fc9e2c3SDag-Erling Smørgrav return 0; 9493fc9e2c3SDag-Erling Smørgrav } 9503fc9e2c3SDag-Erling Smørgrav 9513fc9e2c3SDag-Erling Smørgrav static void 9523fc9e2c3SDag-Erling Smørgrav resolver_set_nameserver_hostname(ldns_resolver *res, const char *server) { 9533fc9e2c3SDag-Erling Smørgrav struct addrinfo hints, *ailist, *ai; 9543fc9e2c3SDag-Erling Smørgrav ldns_status status; 9553fc9e2c3SDag-Erling Smørgrav ldns_rdf *rdf; 9563fc9e2c3SDag-Erling Smørgrav int err; 9573fc9e2c3SDag-Erling Smørgrav 9583fc9e2c3SDag-Erling Smørgrav memset(&hints, 0, sizeof hints); 9593fc9e2c3SDag-Erling Smørgrav switch (ldns_resolver_ip6(res)) { 9603fc9e2c3SDag-Erling Smørgrav case LDNS_RESOLV_INET: hints.ai_family = PF_INET; break; 9613fc9e2c3SDag-Erling Smørgrav case LDNS_RESOLV_INET6: hints.ai_family = PF_INET6; break; 9623fc9e2c3SDag-Erling Smørgrav default: hints.ai_family = PF_UNSPEC; break; 9633fc9e2c3SDag-Erling Smørgrav } 9643fc9e2c3SDag-Erling Smørgrav hints.ai_socktype = SOCK_STREAM; 9653fc9e2c3SDag-Erling Smørgrav do err = getaddrinfo(server, NULL, &hints, &ailist); 9663fc9e2c3SDag-Erling Smørgrav while (err == EAI_AGAIN); 9673fc9e2c3SDag-Erling Smørgrav if (err != 0) 9683fc9e2c3SDag-Erling Smørgrav die(1, "couldn't get address for '%s': %s", server, gai_strerror(err)); 9693fc9e2c3SDag-Erling Smørgrav for (ai = ailist; ai != NULL; ai = ai->ai_next) { 9703fc9e2c3SDag-Erling Smørgrav if ((rdf = ldns_sockaddr_storage2rdf((void*)ai->ai_addr, NULL)) == NULL) 9713fc9e2c3SDag-Erling Smørgrav die(1, "couldn't allocate an rdf: %s", 9723fc9e2c3SDag-Erling Smørgrav ldns_get_errorstr_by_id(LDNS_STATUS_MEM_ERR)); 9733fc9e2c3SDag-Erling Smørgrav status = ldns_resolver_push_nameserver(res, rdf); 9743fc9e2c3SDag-Erling Smørgrav if (status != LDNS_STATUS_OK) 9753fc9e2c3SDag-Erling Smørgrav die(1, "couldn't push a nameserver address: %s", 9763fc9e2c3SDag-Erling Smørgrav ldns_get_errorstr_by_id(status)); 9773fc9e2c3SDag-Erling Smørgrav } 9783fc9e2c3SDag-Erling Smørgrav } 9793fc9e2c3SDag-Erling Smørgrav 9803fc9e2c3SDag-Erling Smørgrav static void 9813fc9e2c3SDag-Erling Smørgrav resolver_set_nameserver_str(ldns_resolver *res, const char *server) { 9823fc9e2c3SDag-Erling Smørgrav ldns_rdf *addr; 9833fc9e2c3SDag-Erling Smørgrav 9843fc9e2c3SDag-Erling Smørgrav ldns_resolver_remove_nameservers(res); 9853fc9e2c3SDag-Erling Smørgrav addr = ldns_rdf_new_addr_frm_str(server); 9863fc9e2c3SDag-Erling Smørgrav if (addr) { 9873fc9e2c3SDag-Erling Smørgrav if (ldns_resolver_push_nameserver(res, addr) != LDNS_STATUS_OK) 9883fc9e2c3SDag-Erling Smørgrav die(1, "couldn't push a nameserver address"); 9893fc9e2c3SDag-Erling Smørgrav } else 9903fc9e2c3SDag-Erling Smørgrav resolver_set_nameserver_hostname(res, server); 9913fc9e2c3SDag-Erling Smørgrav } 9923fc9e2c3SDag-Erling Smørgrav 9933fc9e2c3SDag-Erling Smørgrav int 9943fc9e2c3SDag-Erling Smørgrav main(int argc, char *argv[]) { 9953fc9e2c3SDag-Erling Smørgrav ldns_rdf *addr, *dname; 9963fc9e2c3SDag-Erling Smørgrav ldns_resolver *res; 9973fc9e2c3SDag-Erling Smørgrav ldns_status status; 9983fc9e2c3SDag-Erling Smørgrav struct timeval restimeout; 9993fc9e2c3SDag-Erling Smørgrav 10003fc9e2c3SDag-Erling Smørgrav parse_args(argc, argv); 10013fc9e2c3SDag-Erling Smørgrav 10023fc9e2c3SDag-Erling Smørgrav status = ldns_resolver_new_default(&res); 10033fc9e2c3SDag-Erling Smørgrav if (status != LDNS_STATUS_OK) 10043fc9e2c3SDag-Erling Smørgrav die(1, "error creating resolver: %s", ldns_get_errorstr_by_id(status)); 10053fc9e2c3SDag-Erling Smørgrav if (ldns_resolver_nameserver_count(res) == 0) 10063fc9e2c3SDag-Erling Smørgrav ldns_resolver_push_default_servers(res); 10073fc9e2c3SDag-Erling Smørgrav 10083fc9e2c3SDag-Erling Smørgrav ldns_resolver_set_usevc(res, o_tcp); 10093fc9e2c3SDag-Erling Smørgrav restimeout.tv_sec = o_timeout > 0 ? o_timeout : 10103fc9e2c3SDag-Erling Smørgrav o_tcp ? DEFAULT_TCP_TIMEOUT : DEFAULT_UDP_TIMEOUT; 10113fc9e2c3SDag-Erling Smørgrav restimeout.tv_usec = 0; 10123fc9e2c3SDag-Erling Smørgrav ldns_resolver_set_timeout(res, restimeout); 10133fc9e2c3SDag-Erling Smørgrav ldns_resolver_set_retry(res, o_retries+1); 10143fc9e2c3SDag-Erling Smørgrav ldns_resolver_set_ip6(res, o_ipversion); 10153fc9e2c3SDag-Erling Smørgrav ldns_resolver_set_defnames(res, false); 10163fc9e2c3SDag-Erling Smørgrav ldns_resolver_set_fallback(res, false); 10173fc9e2c3SDag-Erling Smørgrav 10183fc9e2c3SDag-Erling Smørgrav if (o_server) 10193fc9e2c3SDag-Erling Smørgrav resolver_set_nameserver_str(res, o_server); 10203fc9e2c3SDag-Erling Smørgrav 10213fc9e2c3SDag-Erling Smørgrav if (ldns_str2rdf_a(&addr, o_name) == LDNS_STATUS_OK) { 10223fc9e2c3SDag-Erling Smørgrav dname = ldns_rdf_reverse_a(addr, "in-addr.arpa"); 10233fc9e2c3SDag-Erling Smørgrav if (dname == NULL) 10243fc9e2c3SDag-Erling Smørgrav die(1, "can't reverse '%s': %s", o_name, 10253fc9e2c3SDag-Erling Smørgrav ldns_get_errorstr_by_id(LDNS_STATUS_MEM_ERR)); 10263fc9e2c3SDag-Erling Smørgrav o_mode = M_SINGLE_Q; 10273fc9e2c3SDag-Erling Smørgrav o_rrtype = LDNS_RR_TYPE_PTR; 10283fc9e2c3SDag-Erling Smørgrav return !doquery(res, dname); 10293fc9e2c3SDag-Erling Smørgrav } else if (ldns_str2rdf_aaaa(&addr, o_name) == LDNS_STATUS_OK) { 10303fc9e2c3SDag-Erling Smørgrav dname = ldns_rdf_reverse_aaaa(addr, o_ip6_int ? "ip6.int" : "ip6.arpa"); 10313fc9e2c3SDag-Erling Smørgrav if (dname == NULL) 10323fc9e2c3SDag-Erling Smørgrav die(1, "can't reverse '%s': %s", o_name, 10333fc9e2c3SDag-Erling Smørgrav ldns_get_errorstr_by_id(LDNS_STATUS_MEM_ERR)); 10343fc9e2c3SDag-Erling Smørgrav o_mode = M_SINGLE_Q; 10353fc9e2c3SDag-Erling Smørgrav o_rrtype = LDNS_RR_TYPE_PTR; 10363fc9e2c3SDag-Erling Smørgrav return !doquery(res, dname); 10373fc9e2c3SDag-Erling Smørgrav } 1038*3f68b24eSDag-Erling Smørgrav return !(o_mode == M_SOA ? dosoa : 1039*3f68b24eSDag-Erling Smørgrav o_mode == M_AXFR ? dozonetransfer : 1040*3f68b24eSDag-Erling Smørgrav o_mode == M_IXFR ? dozonetransfer : 1041*3f68b24eSDag-Erling Smørgrav dosearch) 10423fc9e2c3SDag-Erling Smørgrav (res, safe_str2rdf_dname(o_name), ndots(o_name) >= o_ndots); 10433fc9e2c3SDag-Erling Smørgrav } 1044