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
103f68b24eSDag-Erling Smørgrav #include <ldns/ldns.h>
113fc9e2c3SDag-Erling Smørgrav #include <limits.h>
123fc9e2c3SDag-Erling Smørgrav #include <netdb.h>
133f68b24eSDag-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
die(int code,const char * fmt,...)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
ndots(const char * name)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
ldns_resolver_new_default(ldns_resolver ** res)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
ldns_resolver_push_default_servers(ldns_resolver * res)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 *
ldns_rdf_new_addr_frm_str(const char * str)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
ldns_resolver_remove_nameservers(ldns_resolver * res)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 *
ldns_rdf_reverse_a(ldns_rdf * addr,const char * base)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 *
ldns_rdf_reverse_aaaa(ldns_rdf * addr,const char * base)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
ldns_pkt_push_rr_soa(ldns_pkt * pkt,ldns_pkt_section sec,const ldns_rdf * name,ldns_rr_class c,uint32_t serial)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
159f4dc9bf4SDag-Erling Smørgrav static uint32_t
ldns_rr_soa_get_serial(const ldns_rr * rr)160f4dc9bf4SDag-Erling Smørgrav ldns_rr_soa_get_serial(const ldns_rr *rr)
161f4dc9bf4SDag-Erling Smørgrav {
162f4dc9bf4SDag-Erling Smørgrav const ldns_rdf *rdf;
163f4dc9bf4SDag-Erling Smørgrav
164f4dc9bf4SDag-Erling Smørgrav if (ldns_rr_get_type(rr) != LDNS_RR_TYPE_SOA) return 0;
165f4dc9bf4SDag-Erling Smørgrav if (ldns_rr_rd_count(rr) != 7) return 0;
166f4dc9bf4SDag-Erling Smørgrav rdf = ldns_rr_rdf(rr, 2);
167f4dc9bf4SDag-Erling Smørgrav if (ldns_rdf_get_type(rdf) != LDNS_RDF_TYPE_INT32) return 0;
168f4dc9bf4SDag-Erling Smørgrav if (ldns_rdf_size(rdf) != 4) return 0;
169f4dc9bf4SDag-Erling Smørgrav return ldns_rdf2native_int32(rdf);
170f4dc9bf4SDag-Erling Smørgrav }
171f4dc9bf4SDag-Erling Smørgrav
1723fc9e2c3SDag-Erling Smørgrav static ldns_status
ldns_tcp_start(ldns_resolver * res,ldns_pkt * qpkt,int nameserver)1733f68b24eSDag-Erling Smørgrav ldns_tcp_start(ldns_resolver *res, ldns_pkt *qpkt, int nameserver) {
1743f68b24eSDag-Erling Smørgrav /* This routine is based on ldns_axfr_start, with the major
1753f68b24eSDag-Erling Smørgrav * difference in that it takes a query packet explicitly.
1763f68b24eSDag-Erling Smørgrav */
1773f68b24eSDag-Erling Smørgrav struct sockaddr_storage *ns = NULL;
1783f68b24eSDag-Erling Smørgrav size_t ns_len = 0;
1793f68b24eSDag-Erling Smørgrav ldns_buffer *qbuf = NULL;
1803f68b24eSDag-Erling Smørgrav ldns_status status;
1813f68b24eSDag-Erling Smørgrav
1823f68b24eSDag-Erling Smørgrav ns = ldns_rdf2native_sockaddr_storage(
1833f68b24eSDag-Erling Smørgrav res->_nameservers[nameserver], ldns_resolver_port(res), &ns_len);
1843f68b24eSDag-Erling Smørgrav if (ns == NULL) {
1853f68b24eSDag-Erling Smørgrav status = LDNS_STATUS_MEM_ERR;
1863f68b24eSDag-Erling Smørgrav goto error;
1873f68b24eSDag-Erling Smørgrav }
1883f68b24eSDag-Erling Smørgrav
1893f68b24eSDag-Erling Smørgrav res->_socket = ldns_tcp_connect(
1903f68b24eSDag-Erling Smørgrav ns, (socklen_t)ns_len, ldns_resolver_timeout(res));
1913f68b24eSDag-Erling Smørgrav if (res->_socket <= 0) {
1923f68b24eSDag-Erling Smørgrav status = LDNS_STATUS_ADDRESS_ERR;
1933f68b24eSDag-Erling Smørgrav goto error;
1943f68b24eSDag-Erling Smørgrav }
1953f68b24eSDag-Erling Smørgrav
1963f68b24eSDag-Erling Smørgrav qbuf = ldns_buffer_new(LDNS_MAX_PACKETLEN);
1973f68b24eSDag-Erling Smørgrav if (qbuf == NULL) {
1983f68b24eSDag-Erling Smørgrav status = LDNS_STATUS_MEM_ERR;
1993f68b24eSDag-Erling Smørgrav goto error;
2003f68b24eSDag-Erling Smørgrav }
2013f68b24eSDag-Erling Smørgrav
2023f68b24eSDag-Erling Smørgrav status = ldns_pkt2buffer_wire(qbuf, qpkt);
2033f68b24eSDag-Erling Smørgrav if (status != LDNS_STATUS_OK)
2043f68b24eSDag-Erling Smørgrav goto error;
2053f68b24eSDag-Erling Smørgrav
2063f68b24eSDag-Erling Smørgrav if (ldns_tcp_send_query(qbuf, res->_socket, ns, (socklen_t)ns_len) == 0) {
2073f68b24eSDag-Erling Smørgrav status = LDNS_STATUS_NETWORK_ERR;
2083f68b24eSDag-Erling Smørgrav goto error;
2093f68b24eSDag-Erling Smørgrav }
2103f68b24eSDag-Erling Smørgrav
2113f68b24eSDag-Erling Smørgrav ldns_buffer_free(qbuf);
2123f68b24eSDag-Erling Smørgrav free(ns);
2133f68b24eSDag-Erling Smørgrav return LDNS_STATUS_OK;
2143f68b24eSDag-Erling Smørgrav
2153f68b24eSDag-Erling Smørgrav error:
2163f68b24eSDag-Erling Smørgrav ldns_buffer_free(qbuf);
2173f68b24eSDag-Erling Smørgrav free(ns);
2183f68b24eSDag-Erling Smørgrav if (res->_socket > 0) {
2193f68b24eSDag-Erling Smørgrav close(res->_socket);
2203f68b24eSDag-Erling Smørgrav res->_socket = 0;
2213f68b24eSDag-Erling Smørgrav }
2223f68b24eSDag-Erling Smørgrav return status;
2233f68b24eSDag-Erling Smørgrav }
2243f68b24eSDag-Erling Smørgrav
2253f68b24eSDag-Erling Smørgrav static ldns_status
ldns_tcp_read(ldns_pkt ** answer,ldns_resolver * res)2263f68b24eSDag-Erling Smørgrav ldns_tcp_read(ldns_pkt **answer, ldns_resolver *res) {
2273f68b24eSDag-Erling Smørgrav ldns_status status;
2283f68b24eSDag-Erling Smørgrav struct timeval t1, t2;
2293f68b24eSDag-Erling Smørgrav uint8_t *data;
2303f68b24eSDag-Erling Smørgrav size_t size;
2313f68b24eSDag-Erling Smørgrav
2323f68b24eSDag-Erling Smørgrav if (res->_socket <= 0)
2333f68b24eSDag-Erling Smørgrav return LDNS_STATUS_ERR;
2343f68b24eSDag-Erling Smørgrav
2353f68b24eSDag-Erling Smørgrav gettimeofday(&t1, NULL);
2363f68b24eSDag-Erling Smørgrav data = ldns_tcp_read_wire_timeout(
2373f68b24eSDag-Erling Smørgrav res->_socket, &size, ldns_resolver_timeout(res));
2383f68b24eSDag-Erling Smørgrav if (data == NULL)
2393f68b24eSDag-Erling Smørgrav goto error;
2403f68b24eSDag-Erling Smørgrav
2413f68b24eSDag-Erling Smørgrav status = ldns_wire2pkt(answer, data, size);
2423f68b24eSDag-Erling Smørgrav free(data);
2433f68b24eSDag-Erling Smørgrav if (status != LDNS_STATUS_OK)
2443f68b24eSDag-Erling Smørgrav goto error;
2453f68b24eSDag-Erling Smørgrav
2463f68b24eSDag-Erling Smørgrav gettimeofday(&t2, NULL);
2473f68b24eSDag-Erling Smørgrav ldns_pkt_set_querytime(*answer,
2483f68b24eSDag-Erling Smørgrav (uint32_t)((t2.tv_sec - t1.tv_sec)*1000) +
2493f68b24eSDag-Erling Smørgrav (t2.tv_usec - t1.tv_usec)/1000);
2503f68b24eSDag-Erling Smørgrav ldns_pkt_set_timestamp(*answer, t2);
2513f68b24eSDag-Erling Smørgrav return status;
2523f68b24eSDag-Erling Smørgrav
2533f68b24eSDag-Erling Smørgrav error:
2543f68b24eSDag-Erling Smørgrav close(res->_socket);
2553f68b24eSDag-Erling Smørgrav res->_socket = 0;
2563f68b24eSDag-Erling Smørgrav return LDNS_STATUS_ERR;
2573f68b24eSDag-Erling Smørgrav }
2583f68b24eSDag-Erling Smørgrav
2593f68b24eSDag-Erling Smørgrav static void
ldns_tcp_close(ldns_resolver * res)2603f68b24eSDag-Erling Smørgrav ldns_tcp_close(ldns_resolver *res) {
2613f68b24eSDag-Erling Smørgrav if (res->_socket > 0) {
2623f68b24eSDag-Erling Smørgrav close(res->_socket);
2633f68b24eSDag-Erling Smørgrav res->_socket = 0;
2643f68b24eSDag-Erling Smørgrav }
2653f68b24eSDag-Erling Smørgrav }
2663f68b24eSDag-Erling Smørgrav
2673f68b24eSDag-Erling Smørgrav static ldns_status
ldns_resolver_send_to(ldns_pkt ** answer,ldns_resolver * res,const ldns_rdf * name,ldns_rr_type t,ldns_rr_class c,uint16_t flags,uint32_t ixfr_serial,int nameserver,bool close_tcp)2683fc9e2c3SDag-Erling Smørgrav ldns_resolver_send_to(ldns_pkt **answer, ldns_resolver *res,
2693fc9e2c3SDag-Erling Smørgrav const ldns_rdf *name, ldns_rr_type t, ldns_rr_class c,
2703f68b24eSDag-Erling Smørgrav uint16_t flags, uint32_t ixfr_serial, int nameserver,
2713f68b24eSDag-Erling Smørgrav bool close_tcp) {
2723f68b24eSDag-Erling Smørgrav ldns_status status = LDNS_STATUS_OK;
2733fc9e2c3SDag-Erling Smørgrav ldns_pkt *qpkt;
2743f68b24eSDag-Erling Smørgrav struct timeval now;
2753fc9e2c3SDag-Erling Smørgrav
2763fc9e2c3SDag-Erling Smørgrav int nscnt = ldns_resolver_nameserver_count(res);
2773fc9e2c3SDag-Erling Smørgrav ldns_rdf **ns = ldns_resolver_nameservers(res);
2783fc9e2c3SDag-Erling Smørgrav size_t *rtt = ldns_resolver_rtt(res);
2793fc9e2c3SDag-Erling Smørgrav
2803fc9e2c3SDag-Erling Smørgrav ldns_resolver_set_nameservers(res, &ns[nameserver]);
2813fc9e2c3SDag-Erling Smørgrav ldns_resolver_set_rtt(res, &rtt[nameserver]);
2823fc9e2c3SDag-Erling Smørgrav ldns_resolver_set_nameserver_count(res, 1);
2833fc9e2c3SDag-Erling Smørgrav
2843f68b24eSDag-Erling Smørgrav /* The next fragment should have been a call to
2853f68b24eSDag-Erling Smørgrav * ldns_resolver_prepare_query_pkt(), but starting with ldns
2863f68b24eSDag-Erling Smørgrav * version 1.6.17 that function tries to add it's own SOA
2873f68b24eSDag-Erling Smørgrav * records when rr_type is LDNS_RR_TYPE_IXFR, and we don't
2883f68b24eSDag-Erling Smørgrav * want that.
2893f68b24eSDag-Erling Smørgrav */
2903f68b24eSDag-Erling Smørgrav qpkt = ldns_pkt_query_new(ldns_rdf_clone(name), t, c, flags);
2913f68b24eSDag-Erling Smørgrav if (qpkt == NULL) {
2923f68b24eSDag-Erling Smørgrav status = LDNS_STATUS_ERR;
2933f68b24eSDag-Erling Smørgrav goto done;
2943f68b24eSDag-Erling Smørgrav }
2953f68b24eSDag-Erling Smørgrav now.tv_sec = time(NULL);
2963f68b24eSDag-Erling Smørgrav now.tv_usec = 0;
2973f68b24eSDag-Erling Smørgrav ldns_pkt_set_timestamp(qpkt, now);
2983f68b24eSDag-Erling Smørgrav ldns_pkt_set_random_id(qpkt);
2993f68b24eSDag-Erling Smørgrav
3003f68b24eSDag-Erling Smørgrav if (t == LDNS_RR_TYPE_IXFR) {
3013fc9e2c3SDag-Erling Smørgrav status = ldns_pkt_push_rr_soa(qpkt,
3023fc9e2c3SDag-Erling Smørgrav LDNS_SECTION_AUTHORITY, name, c, ixfr_serial);
3033f68b24eSDag-Erling Smørgrav if (status != LDNS_STATUS_OK) goto done;
3043f68b24eSDag-Erling Smørgrav }
3053f68b24eSDag-Erling Smørgrav if (close_tcp) {
3063fc9e2c3SDag-Erling Smørgrav status = ldns_resolver_send_pkt(answer, res, qpkt);
3073f68b24eSDag-Erling Smørgrav } else {
3083f68b24eSDag-Erling Smørgrav status = ldns_tcp_start(res, qpkt, 0);
3093f68b24eSDag-Erling Smørgrav if (status != LDNS_STATUS_OK) goto done;
3103f68b24eSDag-Erling Smørgrav status = ldns_tcp_read(answer, res);
3113f68b24eSDag-Erling Smørgrav if (status != LDNS_STATUS_OK) goto done;
3123f68b24eSDag-Erling Smørgrav ldns_pkt_set_answerfrom(*answer, ldns_rdf_clone(ns[0]));
3133f68b24eSDag-Erling Smørgrav }
3143f68b24eSDag-Erling Smørgrav
3153f68b24eSDag-Erling Smørgrav done:
3163fc9e2c3SDag-Erling Smørgrav ldns_pkt_free(qpkt);
3173fc9e2c3SDag-Erling Smørgrav
3183fc9e2c3SDag-Erling Smørgrav ldns_resolver_set_nameservers(res, ns);
3193fc9e2c3SDag-Erling Smørgrav ldns_resolver_set_rtt(res, rtt);
3203fc9e2c3SDag-Erling Smørgrav ldns_resolver_set_nameserver_count(res, nscnt);
3213fc9e2c3SDag-Erling Smørgrav return status;
3223fc9e2c3SDag-Erling Smørgrav }
3233fc9e2c3SDag-Erling Smørgrav
3243fc9e2c3SDag-Erling Smørgrav static void
ldns_pkt_filter_answer(ldns_pkt * pkt,ldns_rr_type type)3253fc9e2c3SDag-Erling Smørgrav ldns_pkt_filter_answer(ldns_pkt *pkt, ldns_rr_type type) {
3263fc9e2c3SDag-Erling Smørgrav int i, j, cnt;
3273fc9e2c3SDag-Erling Smørgrav ldns_rr_list *rrlist;
3283fc9e2c3SDag-Erling Smørgrav ldns_rr *rr;
3293fc9e2c3SDag-Erling Smørgrav ldns_rr_type rrtype;
3303fc9e2c3SDag-Erling Smørgrav
3313fc9e2c3SDag-Erling Smørgrav rrlist = ldns_pkt_answer(pkt);
3323fc9e2c3SDag-Erling Smørgrav cnt = ldns_rr_list_rr_count(rrlist);
3333fc9e2c3SDag-Erling Smørgrav for (i = j = 0; i < cnt; i++) {
3343fc9e2c3SDag-Erling Smørgrav rr = ldns_rr_list_rr(rrlist, i);
3353fc9e2c3SDag-Erling Smørgrav rrtype = ldns_rr_get_type(rr);
3363fc9e2c3SDag-Erling Smørgrav if (type == LDNS_RR_TYPE_ANY ||
3373fc9e2c3SDag-Erling Smørgrav type == rrtype ||
3383fc9e2c3SDag-Erling Smørgrav (type == LDNS_RR_TYPE_AXFR &&
3393fc9e2c3SDag-Erling Smørgrav (rrtype == LDNS_RR_TYPE_A ||
3403fc9e2c3SDag-Erling Smørgrav rrtype == LDNS_RR_TYPE_AAAA ||
3413fc9e2c3SDag-Erling Smørgrav rrtype == LDNS_RR_TYPE_NS ||
3423fc9e2c3SDag-Erling Smørgrav rrtype == LDNS_RR_TYPE_PTR)))
3433fc9e2c3SDag-Erling Smørgrav ldns_rr_list_set_rr(rrlist, rr, j++);
3443fc9e2c3SDag-Erling Smørgrav }
3453fc9e2c3SDag-Erling Smørgrav ldns_rr_list_set_rr_count(rrlist, j);
3463fc9e2c3SDag-Erling Smørgrav }
3473fc9e2c3SDag-Erling Smørgrav
3483fc9e2c3SDag-Erling Smørgrav /* Packet content printing.
3493fc9e2c3SDag-Erling Smørgrav */
3503fc9e2c3SDag-Erling Smørgrav
3513fc9e2c3SDag-Erling Smørgrav static struct {
3523fc9e2c3SDag-Erling Smørgrav ldns_rr_type type;
3533fc9e2c3SDag-Erling Smørgrav const char *text;
3543fc9e2c3SDag-Erling Smørgrav } rr_types[] = {
3553fc9e2c3SDag-Erling Smørgrav {LDNS_RR_TYPE_A, "has address"},
3563fc9e2c3SDag-Erling Smørgrav {LDNS_RR_TYPE_NS, "name server"},
3573fc9e2c3SDag-Erling Smørgrav {LDNS_RR_TYPE_CNAME, "is an alias for"},
3583fc9e2c3SDag-Erling Smørgrav {LDNS_RR_TYPE_WKS, "has well known services"},
3593fc9e2c3SDag-Erling Smørgrav {LDNS_RR_TYPE_PTR, "domain name pointer"},
3603fc9e2c3SDag-Erling Smørgrav {LDNS_RR_TYPE_HINFO, "host information"},
3613fc9e2c3SDag-Erling Smørgrav {LDNS_RR_TYPE_MX, "mail is handled by"},
3623fc9e2c3SDag-Erling Smørgrav {LDNS_RR_TYPE_TXT, "descriptive text"},
3633fc9e2c3SDag-Erling Smørgrav {LDNS_RR_TYPE_X25, "x25 address"},
3643fc9e2c3SDag-Erling Smørgrav {LDNS_RR_TYPE_ISDN, "ISDN address"},
3653fc9e2c3SDag-Erling Smørgrav {LDNS_RR_TYPE_SIG, "has signature"},
3663fc9e2c3SDag-Erling Smørgrav {LDNS_RR_TYPE_KEY, "has key"},
3673fc9e2c3SDag-Erling Smørgrav {LDNS_RR_TYPE_AAAA, "has IPv6 address"},
3683fc9e2c3SDag-Erling Smørgrav {LDNS_RR_TYPE_LOC, "location"},
3693fc9e2c3SDag-Erling Smørgrav };
3703fc9e2c3SDag-Erling Smørgrav
3713fc9e2c3SDag-Erling Smørgrav static void
print_opcode(ldns_pkt_opcode opcode)3723fc9e2c3SDag-Erling Smørgrav print_opcode(ldns_pkt_opcode opcode) {
3733fc9e2c3SDag-Erling Smørgrav ldns_lookup_table *lt = ldns_lookup_by_id(ldns_opcodes, opcode);
3743fc9e2c3SDag-Erling Smørgrav
3753fc9e2c3SDag-Erling Smørgrav if (lt && lt->name)
3763fc9e2c3SDag-Erling Smørgrav printf("%s", lt->name);
3773fc9e2c3SDag-Erling Smørgrav else
3783fc9e2c3SDag-Erling Smørgrav printf("RESERVED%d", opcode);
3793fc9e2c3SDag-Erling Smørgrav }
3803fc9e2c3SDag-Erling Smørgrav
3813fc9e2c3SDag-Erling Smørgrav static void
print_rcode(uint8_t rcode)3823fc9e2c3SDag-Erling Smørgrav print_rcode(uint8_t rcode) {
3833fc9e2c3SDag-Erling Smørgrav ldns_lookup_table *lt = ldns_lookup_by_id(ldns_rcodes, rcode);
3843fc9e2c3SDag-Erling Smørgrav
3853fc9e2c3SDag-Erling Smørgrav if (lt && lt->name)
3863fc9e2c3SDag-Erling Smørgrav printf("%s", lt->name);
3873fc9e2c3SDag-Erling Smørgrav else
3883fc9e2c3SDag-Erling Smørgrav printf("RESERVED%d", rcode);
3893fc9e2c3SDag-Erling Smørgrav }
3903fc9e2c3SDag-Erling Smørgrav
3913fc9e2c3SDag-Erling Smørgrav static int
print_rr_type(ldns_rr_type type)3923fc9e2c3SDag-Erling Smørgrav print_rr_type(ldns_rr_type type) {
3933fc9e2c3SDag-Erling Smørgrav char *str;
3943fc9e2c3SDag-Erling Smørgrav int n;
3953fc9e2c3SDag-Erling Smørgrav
3963fc9e2c3SDag-Erling Smørgrav str = ldns_rr_type2str(type);
3973fc9e2c3SDag-Erling Smørgrav n = printf("%s", str);
3983fc9e2c3SDag-Erling Smørgrav free(str);
3993fc9e2c3SDag-Erling Smørgrav return n;
4003fc9e2c3SDag-Erling Smørgrav }
4013fc9e2c3SDag-Erling Smørgrav
4023fc9e2c3SDag-Erling Smørgrav static int
print_rr_class(ldns_rr_class cls)4033fc9e2c3SDag-Erling Smørgrav print_rr_class(ldns_rr_class cls) {
4043fc9e2c3SDag-Erling Smørgrav char *str;
4053fc9e2c3SDag-Erling Smørgrav int n;
4063fc9e2c3SDag-Erling Smørgrav
4073fc9e2c3SDag-Erling Smørgrav str = ldns_rr_class2str(cls);
4083fc9e2c3SDag-Erling Smørgrav n = printf("%s", str);
4093fc9e2c3SDag-Erling Smørgrav free(str);
4103fc9e2c3SDag-Erling Smørgrav return n;
4113fc9e2c3SDag-Erling Smørgrav }
4123fc9e2c3SDag-Erling Smørgrav
4133fc9e2c3SDag-Erling Smørgrav static int
print_rdf(ldns_rdf * rdf)4143fc9e2c3SDag-Erling Smørgrav print_rdf(ldns_rdf *rdf) {
4153fc9e2c3SDag-Erling Smørgrav char *str;
4163fc9e2c3SDag-Erling Smørgrav int n;
4173fc9e2c3SDag-Erling Smørgrav
4183fc9e2c3SDag-Erling Smørgrav str = ldns_rdf2str(rdf);
4193fc9e2c3SDag-Erling Smørgrav n = printf("%s", str);
4203fc9e2c3SDag-Erling Smørgrav free(str);
4213fc9e2c3SDag-Erling Smørgrav return n;
4223fc9e2c3SDag-Erling Smørgrav }
4233fc9e2c3SDag-Erling Smørgrav
4243fc9e2c3SDag-Erling Smørgrav static int
print_rdf_nodot(ldns_rdf * rdf)4253fc9e2c3SDag-Erling Smørgrav print_rdf_nodot(ldns_rdf *rdf) {
4263fc9e2c3SDag-Erling Smørgrav char *str;
4273fc9e2c3SDag-Erling Smørgrav int len, n;
4283fc9e2c3SDag-Erling Smørgrav
4293fc9e2c3SDag-Erling Smørgrav str = ldns_rdf2str(rdf);
4303fc9e2c3SDag-Erling Smørgrav len = strlen(str);
4313fc9e2c3SDag-Erling Smørgrav n = printf("%.*s", str[len-1] == '.' ? len-1 : len, str);
4323fc9e2c3SDag-Erling Smørgrav free(str);
4333fc9e2c3SDag-Erling Smørgrav return n;
4343fc9e2c3SDag-Erling Smørgrav }
4353fc9e2c3SDag-Erling Smørgrav
4363fc9e2c3SDag-Erling Smørgrav static int
print_padding(int fromcol,int tocol)4373fc9e2c3SDag-Erling Smørgrav print_padding(int fromcol, int tocol) {
4383fc9e2c3SDag-Erling Smørgrav int col = fromcol, nextcol = fromcol + 8 - fromcol%8;
4393fc9e2c3SDag-Erling Smørgrav
4403fc9e2c3SDag-Erling Smørgrav if (fromcol + 1 > tocol) tocol = fromcol + 1;
4413fc9e2c3SDag-Erling Smørgrav for (; nextcol <= tocol; col = nextcol, nextcol += 8)
4423fc9e2c3SDag-Erling Smørgrav printf("\t");
4433fc9e2c3SDag-Erling Smørgrav for (; col < tocol; col++)
4443fc9e2c3SDag-Erling Smørgrav printf(" ");
4453fc9e2c3SDag-Erling Smørgrav return col - fromcol;
4463fc9e2c3SDag-Erling Smørgrav }
4473fc9e2c3SDag-Erling Smørgrav
4483fc9e2c3SDag-Erling Smørgrav static void
print_rr_verbose(ldns_rr * rr)4493fc9e2c3SDag-Erling Smørgrav print_rr_verbose(ldns_rr *rr) {
4503fc9e2c3SDag-Erling Smørgrav bool isq = ldns_rr_is_question(rr);
4513fc9e2c3SDag-Erling Smørgrav int rdcnt = ldns_rr_rd_count(rr);
4523fc9e2c3SDag-Erling Smørgrav int i, n;
4533fc9e2c3SDag-Erling Smørgrav
4543fc9e2c3SDag-Erling Smørgrav /* bind9-host does not count the initial ';' here */
4553fc9e2c3SDag-Erling Smørgrav n = isq ? printf(";") : 0;
4563fc9e2c3SDag-Erling Smørgrav n = print_rdf(ldns_rr_owner(rr));
4573fc9e2c3SDag-Erling Smørgrav if (!isq) {
4583fc9e2c3SDag-Erling Smørgrav n += print_padding(n, 24);
4593fc9e2c3SDag-Erling Smørgrav n += printf("%d", ldns_rr_ttl(rr));
4603fc9e2c3SDag-Erling Smørgrav }
4613fc9e2c3SDag-Erling Smørgrav n += print_padding(n, 32);
4623fc9e2c3SDag-Erling Smørgrav n += print_rr_class(ldns_rr_get_class(rr));
4633fc9e2c3SDag-Erling Smørgrav n += print_padding(n, 40);
4643fc9e2c3SDag-Erling Smørgrav n += print_rr_type(ldns_rr_get_type(rr));
4653fc9e2c3SDag-Erling Smørgrav for (i = 0; i < rdcnt; i++) {
4663fc9e2c3SDag-Erling Smørgrav if (i == 0) print_padding(n, 48);
4673fc9e2c3SDag-Erling Smørgrav else printf(" ");
4683fc9e2c3SDag-Erling Smørgrav print_rdf(ldns_rr_rdf(rr, i));
4693fc9e2c3SDag-Erling Smørgrav }
4703fc9e2c3SDag-Erling Smørgrav printf("\n");
4713fc9e2c3SDag-Erling Smørgrav }
4723fc9e2c3SDag-Erling Smørgrav
4733fc9e2c3SDag-Erling Smørgrav static void
print_pkt_section_verbose(const char * name,ldns_rr_list * rrlist)4743fc9e2c3SDag-Erling Smørgrav print_pkt_section_verbose(const char *name, ldns_rr_list *rrlist) {
4753fc9e2c3SDag-Erling Smørgrav int i, cnt = ldns_rr_list_rr_count(rrlist);
4763fc9e2c3SDag-Erling Smørgrav
4773fc9e2c3SDag-Erling Smørgrav if (cnt == 0)
4783fc9e2c3SDag-Erling Smørgrav return;
4793fc9e2c3SDag-Erling Smørgrav printf(";; %s SECTION:\n", name);
4803fc9e2c3SDag-Erling Smørgrav for (i = 0; i < cnt; i++)
4813fc9e2c3SDag-Erling Smørgrav print_rr_verbose(ldns_rr_list_rr(rrlist, i));
4823fc9e2c3SDag-Erling Smørgrav printf("\n");
4833fc9e2c3SDag-Erling Smørgrav }
4843fc9e2c3SDag-Erling Smørgrav
4853fc9e2c3SDag-Erling Smørgrav static void
print_pkt_verbose(ldns_pkt * pkt)4863fc9e2c3SDag-Erling Smørgrav print_pkt_verbose(ldns_pkt *pkt) {
4873fc9e2c3SDag-Erling Smørgrav int got_flags = 0;
4883fc9e2c3SDag-Erling Smørgrav
4893fc9e2c3SDag-Erling Smørgrav printf(";; ->>HEADER<<- opcode: ");
4903fc9e2c3SDag-Erling Smørgrav print_opcode(ldns_pkt_get_opcode(pkt));
4913fc9e2c3SDag-Erling Smørgrav printf(", status: ");
4923fc9e2c3SDag-Erling Smørgrav print_rcode(ldns_pkt_get_rcode(pkt));
4933fc9e2c3SDag-Erling Smørgrav printf(", id: %u\n", ldns_pkt_id(pkt));
4943fc9e2c3SDag-Erling Smørgrav printf(";; flags:");
4953fc9e2c3SDag-Erling Smørgrav if (ldns_pkt_qr(pkt)) printf(" qr"), got_flags = 1;
4963fc9e2c3SDag-Erling Smørgrav if (ldns_pkt_aa(pkt)) printf(" aa"), got_flags = 1;
4973fc9e2c3SDag-Erling Smørgrav if (ldns_pkt_tc(pkt)) printf(" tc"), got_flags = 1;
4983fc9e2c3SDag-Erling Smørgrav if (ldns_pkt_rd(pkt)) printf(" rd"), got_flags = 1;
4993fc9e2c3SDag-Erling Smørgrav if (ldns_pkt_ra(pkt)) printf(" ra"), got_flags = 1;
5003fc9e2c3SDag-Erling Smørgrav if (ldns_pkt_ad(pkt)) printf(" ad"), got_flags = 1;
5013fc9e2c3SDag-Erling Smørgrav if (ldns_pkt_cd(pkt)) printf(" cd"), got_flags = 1;
5023fc9e2c3SDag-Erling Smørgrav if (!got_flags) printf(" ");
5033fc9e2c3SDag-Erling Smørgrav printf("; QUERY: %u, ANSWER: %u, AUTHORITY: %u, ADDITIONAL: %u\n",
5043fc9e2c3SDag-Erling Smørgrav ldns_pkt_qdcount(pkt), ldns_pkt_ancount(pkt),
5053fc9e2c3SDag-Erling Smørgrav ldns_pkt_nscount(pkt), ldns_pkt_arcount(pkt));
5063fc9e2c3SDag-Erling Smørgrav if (ldns_pkt_edns(pkt))
5073fc9e2c3SDag-Erling Smørgrav printf(";; EDNS: version: %u, udp=%u\n",
5083fc9e2c3SDag-Erling Smørgrav ldns_pkt_edns_version(pkt), ldns_pkt_edns_udp_size(pkt));
5093fc9e2c3SDag-Erling Smørgrav printf("\n");
5103fc9e2c3SDag-Erling Smørgrav print_pkt_section_verbose("QUESTION", ldns_pkt_question(pkt));
5113fc9e2c3SDag-Erling Smørgrav print_pkt_section_verbose("ANSWER", ldns_pkt_answer(pkt));
5123fc9e2c3SDag-Erling Smørgrav print_pkt_section_verbose("AUTHORITY", ldns_pkt_authority(pkt));
5133fc9e2c3SDag-Erling Smørgrav print_pkt_section_verbose("ADDITIONAL", ldns_pkt_additional(pkt));
5143fc9e2c3SDag-Erling Smørgrav }
5153fc9e2c3SDag-Erling Smørgrav
5163fc9e2c3SDag-Erling Smørgrav static void
print_rr_short(ldns_rr * rr)5173fc9e2c3SDag-Erling Smørgrav print_rr_short(ldns_rr *rr) {
5183fc9e2c3SDag-Erling Smørgrav ldns_rr_type type = ldns_rr_get_type(rr);
5193fc9e2c3SDag-Erling Smørgrav size_t i, rdcnt = ldns_rr_rd_count(rr);
5203fc9e2c3SDag-Erling Smørgrav
5213fc9e2c3SDag-Erling Smørgrav print_rdf_nodot(ldns_rr_owner(rr));
5223fc9e2c3SDag-Erling Smørgrav printf(" ");
5233fc9e2c3SDag-Erling Smørgrav for (i = 0; i < countof(rr_types); i++) {
5243fc9e2c3SDag-Erling Smørgrav if (rr_types[i].type == type) {
5253fc9e2c3SDag-Erling Smørgrav printf("%s", rr_types[i].text);
5263fc9e2c3SDag-Erling Smørgrav goto found;
5273fc9e2c3SDag-Erling Smørgrav }
5283fc9e2c3SDag-Erling Smørgrav }
5293fc9e2c3SDag-Erling Smørgrav
5303fc9e2c3SDag-Erling Smørgrav printf("has ");
5313fc9e2c3SDag-Erling Smørgrav print_rr_type(type);
5323fc9e2c3SDag-Erling Smørgrav printf(" record");
5333fc9e2c3SDag-Erling Smørgrav
5343fc9e2c3SDag-Erling Smørgrav found:
5353fc9e2c3SDag-Erling Smørgrav for (i = 0; i < rdcnt; i++) {
5363fc9e2c3SDag-Erling Smørgrav printf(" ");
5373fc9e2c3SDag-Erling Smørgrav print_rdf(ldns_rr_rdf(rr, i));
5383fc9e2c3SDag-Erling Smørgrav }
5393fc9e2c3SDag-Erling Smørgrav printf("\n");
5403fc9e2c3SDag-Erling Smørgrav }
5413fc9e2c3SDag-Erling Smørgrav
5423fc9e2c3SDag-Erling Smørgrav static void
print_pkt_short(ldns_pkt * pkt,bool print_rr_server)5433fc9e2c3SDag-Erling Smørgrav print_pkt_short(ldns_pkt *pkt, bool print_rr_server) {
5443fc9e2c3SDag-Erling Smørgrav ldns_rr_list *rrlist = ldns_pkt_answer(pkt);
5453fc9e2c3SDag-Erling Smørgrav size_t i;
5463fc9e2c3SDag-Erling Smørgrav
5473fc9e2c3SDag-Erling Smørgrav for (i = 0; i < ldns_rr_list_rr_count(rrlist); i++) {
5483fc9e2c3SDag-Erling Smørgrav if (print_rr_server) {
5493fc9e2c3SDag-Erling Smørgrav printf("Nameserver ");
5503fc9e2c3SDag-Erling Smørgrav print_rdf(ldns_pkt_answerfrom(pkt));
5513fc9e2c3SDag-Erling Smørgrav printf(":\n\t");
5523fc9e2c3SDag-Erling Smørgrav }
5533fc9e2c3SDag-Erling Smørgrav print_rr_short(ldns_rr_list_rr(rrlist, i));
5543fc9e2c3SDag-Erling Smørgrav }
5553fc9e2c3SDag-Erling Smørgrav }
5563fc9e2c3SDag-Erling Smørgrav
5573fc9e2c3SDag-Erling Smørgrav static void
print_received_line(ldns_resolver * res,ldns_pkt * pkt)5583fc9e2c3SDag-Erling Smørgrav print_received_line(ldns_resolver *res, ldns_pkt *pkt) {
5593fc9e2c3SDag-Erling Smørgrav char *from = ldns_rdf2str(ldns_pkt_answerfrom(pkt));
5603fc9e2c3SDag-Erling Smørgrav
5613fc9e2c3SDag-Erling Smørgrav printf("Received %zu bytes from %s#%d in %d ms\n",
5623fc9e2c3SDag-Erling Smørgrav ldns_pkt_size(pkt), from, ldns_resolver_port(res),
5633fc9e2c3SDag-Erling Smørgrav ldns_pkt_querytime(pkt));
5643fc9e2c3SDag-Erling Smørgrav free(from);
5653fc9e2c3SDag-Erling Smørgrav }
5663fc9e2c3SDag-Erling Smørgrav
5673fc9e2c3SDag-Erling Smørgrav /* Main program.
5683fc9e2c3SDag-Erling Smørgrav *
5693fc9e2c3SDag-Erling Smørgrav * Note that no memory is freed below this line by intention.
5703fc9e2c3SDag-Erling Smørgrav */
5713fc9e2c3SDag-Erling Smørgrav
5723fc9e2c3SDag-Erling Smørgrav #define DEFAULT_TCP_TIMEOUT 10
5733fc9e2c3SDag-Erling Smørgrav #define DEFAULT_UDP_TIMEOUT 5
5743fc9e2c3SDag-Erling Smørgrav
5753f68b24eSDag-Erling Smørgrav enum operation_mode { M_AXFR, M_IXFR, M_DEFAULT_Q, M_SINGLE_Q, M_SOA };
5763fc9e2c3SDag-Erling Smørgrav
5773fc9e2c3SDag-Erling Smørgrav static enum operation_mode o_mode = M_DEFAULT_Q;
5783fc9e2c3SDag-Erling Smørgrav static bool o_ignore_servfail = true;
5793fc9e2c3SDag-Erling Smørgrav static bool o_ip6_int = false;
5803fc9e2c3SDag-Erling Smørgrav static bool o_print_pkt_server = false;
5813fc9e2c3SDag-Erling Smørgrav static bool o_print_rr_server = false;
5823fc9e2c3SDag-Erling Smørgrav static bool o_recursive = true;
5833fc9e2c3SDag-Erling Smørgrav static bool o_tcp = false;
5843fc9e2c3SDag-Erling Smørgrav static bool o_verbose = false;
5853fc9e2c3SDag-Erling Smørgrav static char *o_name = NULL;
5863fc9e2c3SDag-Erling Smørgrav static char *o_server = NULL;
5873fc9e2c3SDag-Erling Smørgrav static int o_ipversion = LDNS_RESOLV_INETANY;
5883fc9e2c3SDag-Erling Smørgrav static int o_ndots = 1;
5893fc9e2c3SDag-Erling Smørgrav static int o_retries = 1;
5903fc9e2c3SDag-Erling Smørgrav static ldns_rr_class o_rrclass = LDNS_RR_CLASS_IN;
5913f68b24eSDag-Erling Smørgrav static ldns_rr_type o_rrtype = (ldns_rr_type)-1;
5923fc9e2c3SDag-Erling Smørgrav static time_t o_timeout = 0;
5933fc9e2c3SDag-Erling Smørgrav static uint32_t o_ixfr_serial = 0;
5943fc9e2c3SDag-Erling Smørgrav
5953fc9e2c3SDag-Erling Smørgrav static void
usage(void)5963fc9e2c3SDag-Erling Smørgrav usage(void) {
5973f68b24eSDag-Erling Smørgrav fprintf(stderr,
5983f68b24eSDag-Erling Smørgrav "Usage: %s [-aCdilrsTvw46] [-c class] [-N ndots] [-R number]\n"
5993f68b24eSDag-Erling Smørgrav " %*c [-t type] [-W wait] name [server]\n"
6003fc9e2c3SDag-Erling Smørgrav "\t-a same as -v -t ANY\n"
6013fc9e2c3SDag-Erling Smørgrav "\t-C query SOA records from all authoritative name servers\n"
6023fc9e2c3SDag-Erling Smørgrav "\t-c use this query class (IN, CH, HS, etc)\n"
6033fc9e2c3SDag-Erling Smørgrav "\t-d produce verbose output, same as -v\n"
6043fc9e2c3SDag-Erling Smørgrav "\t-i use IP6.INT for IPv6 reverse lookups\n"
6053fc9e2c3SDag-Erling Smørgrav "\t-l list records in a zone via AXFR\n"
6063fc9e2c3SDag-Erling Smørgrav "\t-N consider names with at least this many dots as absolute\n"
6073fc9e2c3SDag-Erling Smørgrav "\t-R retry UDP queries this many times\n"
6083fc9e2c3SDag-Erling Smørgrav "\t-r disable recursive query\n"
6093fc9e2c3SDag-Erling Smørgrav "\t-s do not ignore SERVFAIL responses\n"
6103fc9e2c3SDag-Erling Smørgrav "\t-T send query via TCP\n"
6113fc9e2c3SDag-Erling Smørgrav "\t-t use this query type (A, AAAA, MX, etc)\n"
6123fc9e2c3SDag-Erling Smørgrav "\t-v produce verbose output\n"
6133fc9e2c3SDag-Erling Smørgrav "\t-w wait forever for a server reply\n"
6143fc9e2c3SDag-Erling Smørgrav "\t-W wait this many seconds for a reply\n"
6153fc9e2c3SDag-Erling Smørgrav "\t-4 use IPv4 only\n"
6163fc9e2c3SDag-Erling Smørgrav "\t-6 use IPv6 only\n",
6173f68b24eSDag-Erling Smørgrav progname, (int)strlen(progname), ' ');
6183fc9e2c3SDag-Erling Smørgrav exit(1);
6193fc9e2c3SDag-Erling Smørgrav }
6203fc9e2c3SDag-Erling Smørgrav
6213fc9e2c3SDag-Erling Smørgrav static void
parse_args(int argc,char * argv[])6223fc9e2c3SDag-Erling Smørgrav parse_args(int argc, char *argv[]) {
6233fc9e2c3SDag-Erling Smørgrav int ch;
6243fc9e2c3SDag-Erling Smørgrav
6253fc9e2c3SDag-Erling Smørgrav progname = argv[0];
6263fc9e2c3SDag-Erling Smørgrav while ((ch = getopt(argc, argv, "aCdilrsTvw46c:N:R:t:W:")) != -1) {
6273fc9e2c3SDag-Erling Smørgrav switch (ch) {
6283fc9e2c3SDag-Erling Smørgrav case 'a':
6293fc9e2c3SDag-Erling Smørgrav if (o_mode != M_AXFR)
6303fc9e2c3SDag-Erling Smørgrav o_mode = M_SINGLE_Q;
6313fc9e2c3SDag-Erling Smørgrav o_rrtype = LDNS_RR_TYPE_ANY;
6323fc9e2c3SDag-Erling Smørgrav o_verbose = true;
6333fc9e2c3SDag-Erling Smørgrav break;
6343fc9e2c3SDag-Erling Smørgrav case 'C':
6353fc9e2c3SDag-Erling Smørgrav o_mode = M_SOA;
6363fc9e2c3SDag-Erling Smørgrav o_print_rr_server = true;
6373fc9e2c3SDag-Erling Smørgrav o_rrclass = LDNS_RR_CLASS_IN;
6383fc9e2c3SDag-Erling Smørgrav o_rrtype = LDNS_RR_TYPE_NS;
6393fc9e2c3SDag-Erling Smørgrav break;
6403fc9e2c3SDag-Erling Smørgrav case 'c':
6413fc9e2c3SDag-Erling Smørgrav /* bind9-host sets o_mode to M_SINGLE_Q here */
6423fc9e2c3SDag-Erling Smørgrav o_rrclass = ldns_get_rr_class_by_name(optarg);
6433fc9e2c3SDag-Erling Smørgrav if (o_rrclass <= 0)
6443fc9e2c3SDag-Erling Smørgrav die(2, "invalid class: %s\n", optarg);
6453fc9e2c3SDag-Erling Smørgrav break;
6463fc9e2c3SDag-Erling Smørgrav case 'd': o_verbose = true; break;
6473fc9e2c3SDag-Erling Smørgrav case 'i': o_ip6_int = true; break;
6483fc9e2c3SDag-Erling Smørgrav case 'l':
6493fc9e2c3SDag-Erling Smørgrav o_mode = M_AXFR;
6503f68b24eSDag-Erling Smørgrav if (o_rrtype == (ldns_rr_type)-1)
6513fc9e2c3SDag-Erling Smørgrav o_rrtype = LDNS_RR_TYPE_AXFR;
6523fc9e2c3SDag-Erling Smørgrav o_tcp = true;
6533fc9e2c3SDag-Erling Smørgrav break;
6543fc9e2c3SDag-Erling Smørgrav case 'N':
6553fc9e2c3SDag-Erling Smørgrav o_ndots = atoi(optarg);
6563fc9e2c3SDag-Erling Smørgrav if (o_ndots < 0) o_ndots = 0;
6573fc9e2c3SDag-Erling Smørgrav break;
6583fc9e2c3SDag-Erling Smørgrav case 'n':
6593fc9e2c3SDag-Erling Smørgrav /* bind9-host accepts and ignores this option */
6603fc9e2c3SDag-Erling Smørgrav break;
6613fc9e2c3SDag-Erling Smørgrav case 'r': o_recursive = 0; break;
6623fc9e2c3SDag-Erling Smørgrav case 'R':
6633fc9e2c3SDag-Erling Smørgrav o_retries = atoi(optarg);
6643fc9e2c3SDag-Erling Smørgrav if (o_retries <= 0) o_retries = 1;
6653fc9e2c3SDag-Erling Smørgrav if (o_retries > 255) o_retries = 255;
6663fc9e2c3SDag-Erling Smørgrav break;
6673fc9e2c3SDag-Erling Smørgrav case 's': o_ignore_servfail = false; break;
6683fc9e2c3SDag-Erling Smørgrav case 'T': o_tcp = true; break;
6693fc9e2c3SDag-Erling Smørgrav case 't':
6703fc9e2c3SDag-Erling Smørgrav if (o_mode != M_AXFR)
6713fc9e2c3SDag-Erling Smørgrav o_mode = M_SINGLE_Q;
6723fc9e2c3SDag-Erling Smørgrav if (strncasecmp(optarg, "ixfr=", 5) == 0) {
6733fc9e2c3SDag-Erling Smørgrav o_rrtype = LDNS_RR_TYPE_IXFR;
6743fc9e2c3SDag-Erling Smørgrav o_ixfr_serial = atol(optarg + 5);
6753fc9e2c3SDag-Erling Smørgrav } else {
6763fc9e2c3SDag-Erling Smørgrav o_rrtype = ldns_get_rr_type_by_name(optarg);
6773fc9e2c3SDag-Erling Smørgrav if (o_rrtype <= 0)
6783fc9e2c3SDag-Erling Smørgrav die(2, "invalid type: %s\n", optarg);
6793fc9e2c3SDag-Erling Smørgrav }
6803fc9e2c3SDag-Erling Smørgrav if (o_rrtype == LDNS_RR_TYPE_AXFR) {
6813fc9e2c3SDag-Erling Smørgrav o_mode = M_AXFR;
6823fc9e2c3SDag-Erling Smørgrav o_rrtype = LDNS_RR_TYPE_ANY;
6833fc9e2c3SDag-Erling Smørgrav o_verbose = true;
6843fc9e2c3SDag-Erling Smørgrav }
6853f68b24eSDag-Erling Smørgrav if (o_rrtype == LDNS_RR_TYPE_IXFR) {
6863f68b24eSDag-Erling Smørgrav o_mode = M_IXFR;
6873f68b24eSDag-Erling Smørgrav o_rrtype = LDNS_RR_TYPE_ANY;
6883f68b24eSDag-Erling Smørgrav }
6893fc9e2c3SDag-Erling Smørgrav break;
6903fc9e2c3SDag-Erling Smørgrav case 'v': o_verbose = true; break;
6913fc9e2c3SDag-Erling Smørgrav case 'w':
6923fc9e2c3SDag-Erling Smørgrav o_timeout = (time_t)INT_MAX;
6933fc9e2c3SDag-Erling Smørgrav break;
6943fc9e2c3SDag-Erling Smørgrav case 'W':
6953fc9e2c3SDag-Erling Smørgrav o_timeout = atol(optarg);
6963fc9e2c3SDag-Erling Smørgrav if (o_timeout <= 0) o_timeout = 1;
6973fc9e2c3SDag-Erling Smørgrav break;
6983fc9e2c3SDag-Erling Smørgrav case '4': o_ipversion = LDNS_RESOLV_INET; break;
6993fc9e2c3SDag-Erling Smørgrav case '6': o_ipversion = LDNS_RESOLV_INET6; break;
7003fc9e2c3SDag-Erling Smørgrav default:
7013fc9e2c3SDag-Erling Smørgrav usage();
7023fc9e2c3SDag-Erling Smørgrav }
7033fc9e2c3SDag-Erling Smørgrav }
7043fc9e2c3SDag-Erling Smørgrav argc -= optind;
7053fc9e2c3SDag-Erling Smørgrav argv += optind;
7063fc9e2c3SDag-Erling Smørgrav /* bind9-host ignores arguments after the 2-nd one */
7073fc9e2c3SDag-Erling Smørgrav if (argc < 1)
7083fc9e2c3SDag-Erling Smørgrav usage();
7093fc9e2c3SDag-Erling Smørgrav o_name = argv[0];
7103fc9e2c3SDag-Erling Smørgrav if (argc > 1) {
7113fc9e2c3SDag-Erling Smørgrav o_server = argv[1];
7123fc9e2c3SDag-Erling Smørgrav o_print_pkt_server = true;
7133fc9e2c3SDag-Erling Smørgrav }
7143f68b24eSDag-Erling Smørgrav if (o_rrtype == (ldns_rr_type)-1)
7153f68b24eSDag-Erling Smørgrav o_rrtype = LDNS_RR_TYPE_A;
7163fc9e2c3SDag-Erling Smørgrav }
7173fc9e2c3SDag-Erling Smørgrav
7183fc9e2c3SDag-Erling Smørgrav static ldns_rdf*
safe_str2rdf_dname(const char * name)7193fc9e2c3SDag-Erling Smørgrav safe_str2rdf_dname(const char *name) {
7203fc9e2c3SDag-Erling Smørgrav ldns_rdf *dname;
7213fc9e2c3SDag-Erling Smørgrav ldns_status status;
7223fc9e2c3SDag-Erling Smørgrav
7233fc9e2c3SDag-Erling Smørgrav if ((status = ldns_str2rdf_dname(&dname, name)) != LDNS_STATUS_OK) {
7243fc9e2c3SDag-Erling Smørgrav die(1, "'%s' is not a legal name (%s)",
7253fc9e2c3SDag-Erling Smørgrav name, ldns_get_errorstr_by_id(status));
7263fc9e2c3SDag-Erling Smørgrav }
7273fc9e2c3SDag-Erling Smørgrav return dname;
7283fc9e2c3SDag-Erling Smørgrav }
7293fc9e2c3SDag-Erling Smørgrav
7303fc9e2c3SDag-Erling Smørgrav static ldns_rdf*
safe_dname_cat_clone(const ldns_rdf * rd1,const ldns_rdf * rd2)7313fc9e2c3SDag-Erling Smørgrav safe_dname_cat_clone(const ldns_rdf *rd1, const ldns_rdf *rd2) {
7323fc9e2c3SDag-Erling Smørgrav ldns_rdf *result = ldns_dname_cat_clone(rd1, rd2);
7333fc9e2c3SDag-Erling Smørgrav
7343fc9e2c3SDag-Erling Smørgrav if (!result)
7353fc9e2c3SDag-Erling Smørgrav die(1, "not enought memory for a domain name");
7363fc9e2c3SDag-Erling Smørgrav /* Why doesn't ldns_dname_cat_clone check this condition? */
7373fc9e2c3SDag-Erling Smørgrav if (ldns_rdf_size(result) > LDNS_MAX_DOMAINLEN)
7383fc9e2c3SDag-Erling Smørgrav die(1, "'%s' is not a legal name (%s)\n", ldns_rdf2str(result),
7393fc9e2c3SDag-Erling Smørgrav ldns_get_errorstr_by_id(LDNS_STATUS_DOMAINNAME_OVERFLOW));
7403fc9e2c3SDag-Erling Smørgrav return result;
7413fc9e2c3SDag-Erling Smørgrav }
7423fc9e2c3SDag-Erling Smørgrav
7433fc9e2c3SDag-Erling Smørgrav static bool
query(ldns_resolver * res,ldns_rdf * domain,ldns_pkt ** pkt,bool close_tcp)7443f68b24eSDag-Erling Smørgrav query(ldns_resolver *res, ldns_rdf *domain, ldns_pkt **pkt, bool close_tcp) {
7453fc9e2c3SDag-Erling Smørgrav ldns_status status;
7463fc9e2c3SDag-Erling Smørgrav ldns_pkt_rcode rcode;
7473fc9e2c3SDag-Erling Smørgrav int i, cnt;
7483fc9e2c3SDag-Erling Smørgrav
7493fc9e2c3SDag-Erling Smørgrav if (o_verbose) {
7503fc9e2c3SDag-Erling Smørgrav printf("Trying \"");
7513fc9e2c3SDag-Erling Smørgrav print_rdf_nodot(domain);
7523fc9e2c3SDag-Erling Smørgrav printf("\"\n");
7533fc9e2c3SDag-Erling Smørgrav }
7543fc9e2c3SDag-Erling Smørgrav for (cnt = ldns_resolver_nameserver_count(res), i = 0; i < cnt; i++) {
7553fc9e2c3SDag-Erling Smørgrav status = ldns_resolver_send_to(pkt, res, domain, o_rrtype,
7563f68b24eSDag-Erling Smørgrav o_rrclass, o_recursive ? LDNS_RD : 0, o_ixfr_serial, i,
7573f68b24eSDag-Erling Smørgrav close_tcp);
7583fc9e2c3SDag-Erling Smørgrav if (status != LDNS_STATUS_OK) {
7593fc9e2c3SDag-Erling Smørgrav *pkt = NULL;
7603fc9e2c3SDag-Erling Smørgrav continue;
7613fc9e2c3SDag-Erling Smørgrav }
7623fc9e2c3SDag-Erling Smørgrav if (ldns_pkt_tc(*pkt) && !ldns_resolver_usevc(res)) {
7633fc9e2c3SDag-Erling Smørgrav if (o_verbose)
7643fc9e2c3SDag-Erling Smørgrav printf(";; Truncated, retrying in TCP mode.\n");
7653fc9e2c3SDag-Erling Smørgrav ldns_resolver_set_usevc(res, true);
7663fc9e2c3SDag-Erling Smørgrav status = ldns_resolver_send_to(pkt, res, domain, o_rrtype,
7673f68b24eSDag-Erling Smørgrav o_rrclass, o_recursive ? LDNS_RD : 0, o_ixfr_serial, i,
7683f68b24eSDag-Erling Smørgrav close_tcp);
7693fc9e2c3SDag-Erling Smørgrav ldns_resolver_set_usevc(res, false);
7703fc9e2c3SDag-Erling Smørgrav if (status != LDNS_STATUS_OK)
7713fc9e2c3SDag-Erling Smørgrav continue;
7723fc9e2c3SDag-Erling Smørgrav }
7733fc9e2c3SDag-Erling Smørgrav rcode = ldns_pkt_get_rcode(*pkt);
7743fc9e2c3SDag-Erling Smørgrav if (o_ignore_servfail && rcode == LDNS_RCODE_SERVFAIL && cnt > 1)
7753fc9e2c3SDag-Erling Smørgrav continue;
7763fc9e2c3SDag-Erling Smørgrav return rcode == LDNS_RCODE_NOERROR;
7773fc9e2c3SDag-Erling Smørgrav }
7783fc9e2c3SDag-Erling Smørgrav if (*pkt == NULL) {
7793fc9e2c3SDag-Erling Smørgrav printf(";; connection timed out; no servers could be reached\n");
7803fc9e2c3SDag-Erling Smørgrav exit(1);
7813fc9e2c3SDag-Erling Smørgrav }
7823fc9e2c3SDag-Erling Smørgrav return false;
7833fc9e2c3SDag-Erling Smørgrav }
7843fc9e2c3SDag-Erling Smørgrav
7853fc9e2c3SDag-Erling Smørgrav static ldns_rdf *
search(ldns_resolver * res,ldns_rdf * domain,ldns_pkt ** pkt,bool absolute,bool close_tcp)7863f68b24eSDag-Erling Smørgrav search(ldns_resolver *res, ldns_rdf *domain, ldns_pkt **pkt,
7873f68b24eSDag-Erling Smørgrav bool absolute, bool close_tcp) {
7883fc9e2c3SDag-Erling Smørgrav ldns_rdf *dname, **searchlist;
7893fc9e2c3SDag-Erling Smørgrav int i, n;
7903fc9e2c3SDag-Erling Smørgrav
7913f68b24eSDag-Erling Smørgrav if (absolute && query(res, domain, pkt, close_tcp))
7923fc9e2c3SDag-Erling Smørgrav return domain;
7933fc9e2c3SDag-Erling Smørgrav
7943fc9e2c3SDag-Erling Smørgrav if ((dname = ldns_resolver_domain(res)) != NULL) {
7953fc9e2c3SDag-Erling Smørgrav dname = safe_dname_cat_clone(domain, dname);
7963f68b24eSDag-Erling Smørgrav if (query(res, dname, pkt, close_tcp))
7973fc9e2c3SDag-Erling Smørgrav return dname;
7983fc9e2c3SDag-Erling Smørgrav }
7993fc9e2c3SDag-Erling Smørgrav
8003fc9e2c3SDag-Erling Smørgrav searchlist = ldns_resolver_searchlist(res);
8013fc9e2c3SDag-Erling Smørgrav n = ldns_resolver_searchlist_count(res);
8023fc9e2c3SDag-Erling Smørgrav for (i = 0; i < n; i++) {
8033fc9e2c3SDag-Erling Smørgrav dname = safe_dname_cat_clone(domain, searchlist[i]);
8043f68b24eSDag-Erling Smørgrav if (query(res, dname, pkt, close_tcp))
8053fc9e2c3SDag-Erling Smørgrav return dname;
8063fc9e2c3SDag-Erling Smørgrav }
8073fc9e2c3SDag-Erling Smørgrav
8083f68b24eSDag-Erling Smørgrav if (!absolute && query(res, domain, pkt, close_tcp))
8093fc9e2c3SDag-Erling Smørgrav return domain;
8103fc9e2c3SDag-Erling Smørgrav
8113fc9e2c3SDag-Erling Smørgrav return NULL;
8123fc9e2c3SDag-Erling Smørgrav }
8133fc9e2c3SDag-Erling Smørgrav
8143fc9e2c3SDag-Erling Smørgrav static void
report(ldns_resolver * res,ldns_rdf * domain,ldns_pkt * pkt)8153fc9e2c3SDag-Erling Smørgrav report(ldns_resolver *res, ldns_rdf *domain, ldns_pkt *pkt) {
8163fc9e2c3SDag-Erling Smørgrav ldns_pkt_rcode rcode;
8173fc9e2c3SDag-Erling Smørgrav
8183fc9e2c3SDag-Erling Smørgrav if (o_print_pkt_server) {
8193fc9e2c3SDag-Erling Smørgrav printf("Using domain server:\nName: %s\nAddress: ", o_server);
8203fc9e2c3SDag-Erling Smørgrav print_rdf(ldns_pkt_answerfrom(pkt));
8213fc9e2c3SDag-Erling Smørgrav printf("#%d\nAliases: \n\n", ldns_resolver_port(res));
8223fc9e2c3SDag-Erling Smørgrav o_print_pkt_server = false;
8233fc9e2c3SDag-Erling Smørgrav }
8243fc9e2c3SDag-Erling Smørgrav rcode = ldns_pkt_get_rcode(pkt);
8253fc9e2c3SDag-Erling Smørgrav if (rcode != LDNS_RCODE_NOERROR) {
8263fc9e2c3SDag-Erling Smørgrav printf("Host ");
8273fc9e2c3SDag-Erling Smørgrav print_rdf_nodot(domain);
8283fc9e2c3SDag-Erling Smørgrav printf(" not found: %d(", rcode);
8293fc9e2c3SDag-Erling Smørgrav print_rcode(rcode);
8303fc9e2c3SDag-Erling Smørgrav printf(")\n");
8313fc9e2c3SDag-Erling Smørgrav } else {
8323fc9e2c3SDag-Erling Smørgrav if (o_verbose) {
8333fc9e2c3SDag-Erling Smørgrav print_pkt_verbose(pkt);
8343fc9e2c3SDag-Erling Smørgrav } else {
8353fc9e2c3SDag-Erling Smørgrav print_pkt_short(pkt, o_print_rr_server);
8363f68b24eSDag-Erling Smørgrav if (o_mode == M_SINGLE_Q &&
8373fc9e2c3SDag-Erling Smørgrav ldns_rr_list_rr_count(ldns_pkt_answer(pkt)) == 0) {
8383fc9e2c3SDag-Erling Smørgrav print_rdf_nodot(domain);
8393fc9e2c3SDag-Erling Smørgrav printf(" has no ");
8403fc9e2c3SDag-Erling Smørgrav print_rr_type(o_rrtype);
8413fc9e2c3SDag-Erling Smørgrav printf(" record\n");
8423fc9e2c3SDag-Erling Smørgrav }
8433fc9e2c3SDag-Erling Smørgrav }
8443fc9e2c3SDag-Erling Smørgrav }
8453fc9e2c3SDag-Erling Smørgrav if (o_verbose)
8463fc9e2c3SDag-Erling Smørgrav print_received_line(res, pkt);
8473fc9e2c3SDag-Erling Smørgrav }
8483fc9e2c3SDag-Erling Smørgrav
8493fc9e2c3SDag-Erling Smørgrav static bool
doquery(ldns_resolver * res,ldns_rdf * domain)8503fc9e2c3SDag-Erling Smørgrav doquery(ldns_resolver *res, ldns_rdf *domain) {
8513fc9e2c3SDag-Erling Smørgrav ldns_pkt *pkt;
8523fc9e2c3SDag-Erling Smørgrav bool q;
8533fc9e2c3SDag-Erling Smørgrav
8543f68b24eSDag-Erling Smørgrav q = query(res, domain, &pkt, true);
8553fc9e2c3SDag-Erling Smørgrav report(res, domain, pkt);
8563fc9e2c3SDag-Erling Smørgrav return q;
8573fc9e2c3SDag-Erling Smørgrav }
8583fc9e2c3SDag-Erling Smørgrav
8593fc9e2c3SDag-Erling Smørgrav static bool
doquery_filtered(ldns_resolver * res,ldns_rdf * domain)8603fc9e2c3SDag-Erling Smørgrav doquery_filtered(ldns_resolver *res, ldns_rdf *domain) {
8613fc9e2c3SDag-Erling Smørgrav ldns_pkt *pkt;
8623fc9e2c3SDag-Erling Smørgrav bool q;
8633fc9e2c3SDag-Erling Smørgrav
8643f68b24eSDag-Erling Smørgrav q = query(res, domain, &pkt, true);
8653fc9e2c3SDag-Erling Smørgrav ldns_pkt_filter_answer(pkt, o_rrtype);
8663fc9e2c3SDag-Erling Smørgrav report(res, domain, pkt);
8673fc9e2c3SDag-Erling Smørgrav return q;
8683fc9e2c3SDag-Erling Smørgrav }
8693fc9e2c3SDag-Erling Smørgrav
8703fc9e2c3SDag-Erling Smørgrav static bool
dosearch(ldns_resolver * res,ldns_rdf * domain,bool absolute)8713fc9e2c3SDag-Erling Smørgrav dosearch(ldns_resolver *res, ldns_rdf *domain, bool absolute) {
8723fc9e2c3SDag-Erling Smørgrav ldns_pkt *pkt;
8733fc9e2c3SDag-Erling Smørgrav ldns_rdf *dname;
8743fc9e2c3SDag-Erling Smørgrav
8753f68b24eSDag-Erling Smørgrav dname = search(res, domain, &pkt, absolute, true);
8763fc9e2c3SDag-Erling Smørgrav report(res, dname != NULL ? dname : domain, pkt);
8773fc9e2c3SDag-Erling Smørgrav return o_mode != M_DEFAULT_Q ? (dname != NULL) :
8783fc9e2c3SDag-Erling Smørgrav (dname != NULL) &&
8793fc9e2c3SDag-Erling Smørgrav (o_rrtype = LDNS_RR_TYPE_AAAA, doquery_filtered(res, dname)) &&
8803fc9e2c3SDag-Erling Smørgrav (o_rrtype = LDNS_RR_TYPE_MX, doquery_filtered(res, dname));
8813fc9e2c3SDag-Erling Smørgrav }
8823fc9e2c3SDag-Erling Smørgrav
8833fc9e2c3SDag-Erling Smørgrav static bool
dozonetransfer(ldns_resolver * res,ldns_rdf * domain,bool absolute)8843f68b24eSDag-Erling Smørgrav dozonetransfer(ldns_resolver *res, ldns_rdf *domain, bool absolute) {
8853f68b24eSDag-Erling Smørgrav ldns_pkt *pkt, *nextpkt;
8863fc9e2c3SDag-Erling Smørgrav ldns_rdf *dname;
8873fc9e2c3SDag-Erling Smørgrav ldns_rr_type rrtype;
8883f68b24eSDag-Erling Smørgrav ldns_rr_list *rrl;
889f4dc9bf4SDag-Erling Smørgrav ldns_rr *rr;
890f4dc9bf4SDag-Erling Smørgrav size_t i, nsoa = 0;
891*1c4f5adbSEnji Cooper uint32_t first_serial = 0;
8923fc9e2c3SDag-Erling Smørgrav
8933fc9e2c3SDag-Erling Smørgrav rrtype = o_rrtype;
8943f68b24eSDag-Erling Smørgrav o_rrtype = (o_mode == M_AXFR) ? LDNS_RR_TYPE_AXFR : LDNS_RR_TYPE_IXFR;
8953f68b24eSDag-Erling Smørgrav dname = search(res, domain, &pkt, absolute, false);
8963f68b24eSDag-Erling Smørgrav
8973f68b24eSDag-Erling Smørgrav for (;;) {
898f4dc9bf4SDag-Erling Smørgrav rrl = ldns_rr_list_clone(ldns_pkt_answer(pkt));
8993fc9e2c3SDag-Erling Smørgrav ldns_pkt_filter_answer(pkt, rrtype);
9003fc9e2c3SDag-Erling Smørgrav report(res, dname != NULL ? dname : domain, pkt);
9013f68b24eSDag-Erling Smørgrav if ((dname == NULL) ||
9023f68b24eSDag-Erling Smørgrav (ldns_pkt_get_rcode(pkt) != LDNS_RCODE_NOERROR)) {
9033f68b24eSDag-Erling Smørgrav printf("; Transfer failed.\n");
9043f68b24eSDag-Erling Smørgrav ldns_tcp_close(res);
9053f68b24eSDag-Erling Smørgrav return false;
9063f68b24eSDag-Erling Smørgrav }
907f4dc9bf4SDag-Erling Smørgrav for (i = 0; i < ldns_rr_list_rr_count(rrl); i++) {
908f4dc9bf4SDag-Erling Smørgrav rr = ldns_rr_list_rr(rrl, i);
909f4dc9bf4SDag-Erling Smørgrav if (nsoa == 0) {
910f4dc9bf4SDag-Erling Smørgrav if (ldns_rr_get_type(rr) != LDNS_RR_TYPE_SOA) {
911f4dc9bf4SDag-Erling Smørgrav printf("; Transfer failed. "
912f4dc9bf4SDag-Erling Smørgrav "Didn't start with SOA answer.\n");
913f4dc9bf4SDag-Erling Smørgrav ldns_tcp_close(res);
914f4dc9bf4SDag-Erling Smørgrav return false;
915f4dc9bf4SDag-Erling Smørgrav }
916f4dc9bf4SDag-Erling Smørgrav first_serial = ldns_rr_soa_get_serial(rr);
917f4dc9bf4SDag-Erling Smørgrav if ((o_mode == M_IXFR) && (first_serial <= o_ixfr_serial)) {
9183f68b24eSDag-Erling Smørgrav ldns_tcp_close(res);
9193f68b24eSDag-Erling Smørgrav return true;
9203f68b24eSDag-Erling Smørgrav }
921f4dc9bf4SDag-Erling Smørgrav }
922f4dc9bf4SDag-Erling Smørgrav if (ldns_rr_get_type(rr) == LDNS_RR_TYPE_SOA) {
923f4dc9bf4SDag-Erling Smørgrav nsoa = nsoa < 2 ? nsoa + 1 : 1;
924f4dc9bf4SDag-Erling Smørgrav if ((nsoa == 2) &&
925f4dc9bf4SDag-Erling Smørgrav (ldns_rr_soa_get_serial(rr) == first_serial)) {
926f4dc9bf4SDag-Erling Smørgrav ldns_tcp_close(res);
927f4dc9bf4SDag-Erling Smørgrav return true;
928f4dc9bf4SDag-Erling Smørgrav }
929f4dc9bf4SDag-Erling Smørgrav }
930f4dc9bf4SDag-Erling Smørgrav }
9313f68b24eSDag-Erling Smørgrav if (ldns_tcp_read(&nextpkt, res) != LDNS_STATUS_OK) {
9323f68b24eSDag-Erling Smørgrav printf("; Transfer failed.\n");
9333f68b24eSDag-Erling Smørgrav return false;
9343f68b24eSDag-Erling Smørgrav }
9353f68b24eSDag-Erling Smørgrav ldns_pkt_set_answerfrom(nextpkt,
9363f68b24eSDag-Erling Smørgrav ldns_rdf_clone(ldns_pkt_answerfrom(pkt)));
9373f68b24eSDag-Erling Smørgrav ldns_pkt_free(pkt);
938f4dc9bf4SDag-Erling Smørgrav ldns_rr_list_free(rrl);
9393f68b24eSDag-Erling Smørgrav pkt = nextpkt;
9403f68b24eSDag-Erling Smørgrav }
9413fc9e2c3SDag-Erling Smørgrav }
9423fc9e2c3SDag-Erling Smørgrav
9433fc9e2c3SDag-Erling Smørgrav static bool
dosoa(ldns_resolver * res,ldns_rdf * domain,bool absolute)9443fc9e2c3SDag-Erling Smørgrav dosoa(ldns_resolver *res, ldns_rdf *domain, bool absolute) {
9453fc9e2c3SDag-Erling Smørgrav ldns_rr_list *answer, **nsaddrs;
9463fc9e2c3SDag-Erling Smørgrav ldns_rdf *dname, *addr;
9473fc9e2c3SDag-Erling Smørgrav ldns_pkt *pkt;
9483fc9e2c3SDag-Erling Smørgrav ldns_rr *rr;
9493fc9e2c3SDag-Erling Smørgrav size_t i, j, n, cnt;
9503fc9e2c3SDag-Erling Smørgrav
9513f68b24eSDag-Erling Smørgrav if ((dname = search(res, domain, &pkt, absolute, true)) == NULL)
9523fc9e2c3SDag-Erling Smørgrav return false;
9533fc9e2c3SDag-Erling Smørgrav
9543fc9e2c3SDag-Erling Smørgrav answer = ldns_pkt_answer(pkt);
9553fc9e2c3SDag-Erling Smørgrav cnt = ldns_rr_list_rr_count(answer);
9563fc9e2c3SDag-Erling Smørgrav nsaddrs = alloca(cnt*sizeof(*nsaddrs));
9573fc9e2c3SDag-Erling Smørgrav for (n = 0, i = 0; i < cnt; i++)
9583fc9e2c3SDag-Erling Smørgrav if ((addr = ldns_rr_ns_nsdname(ldns_rr_list_rr(answer, i))) != NULL)
9593fc9e2c3SDag-Erling Smørgrav nsaddrs[n++] = ldns_get_rr_list_addr_by_name(res,
9603fc9e2c3SDag-Erling Smørgrav addr, LDNS_RR_CLASS_IN, 0);
9613fc9e2c3SDag-Erling Smørgrav
9623fc9e2c3SDag-Erling Smørgrav o_print_pkt_server = false;
9633fc9e2c3SDag-Erling Smørgrav o_recursive = false;
9643fc9e2c3SDag-Erling Smørgrav o_rrtype = LDNS_RR_TYPE_SOA;
9653fc9e2c3SDag-Erling Smørgrav for (i = 0; i < n; i++) {
9663fc9e2c3SDag-Erling Smørgrav cnt = ldns_rr_list_rr_count(nsaddrs[i]);
9673fc9e2c3SDag-Erling Smørgrav for (j = 0; j < cnt; j++) {
9683fc9e2c3SDag-Erling Smørgrav ldns_resolver_remove_nameservers(res);
9693fc9e2c3SDag-Erling Smørgrav rr = ldns_rr_list_rr(nsaddrs[i], j);
9703fc9e2c3SDag-Erling Smørgrav if ((ldns_resolver_ip6(res) == LDNS_RESOLV_INET &&
9713fc9e2c3SDag-Erling Smørgrav ldns_rr_get_type(rr) == LDNS_RR_TYPE_AAAA) ||
9723fc9e2c3SDag-Erling Smørgrav (ldns_resolver_ip6(res) == LDNS_RESOLV_INET6 &&
9733fc9e2c3SDag-Erling Smørgrav ldns_rr_get_type(rr) == LDNS_RR_TYPE_A))
9743fc9e2c3SDag-Erling Smørgrav continue;
9753fc9e2c3SDag-Erling Smørgrav if (ldns_resolver_push_nameserver_rr(res, rr) == LDNS_STATUS_OK)
9763fc9e2c3SDag-Erling Smørgrav /* bind9-host queries for domain, not dname here */
9773fc9e2c3SDag-Erling Smørgrav doquery(res, dname);
9783fc9e2c3SDag-Erling Smørgrav }
9793fc9e2c3SDag-Erling Smørgrav }
9803fc9e2c3SDag-Erling Smørgrav return 0;
9813fc9e2c3SDag-Erling Smørgrav }
9823fc9e2c3SDag-Erling Smørgrav
9833fc9e2c3SDag-Erling Smørgrav static void
resolver_set_nameserver_hostname(ldns_resolver * res,const char * server)9843fc9e2c3SDag-Erling Smørgrav resolver_set_nameserver_hostname(ldns_resolver *res, const char *server) {
9853fc9e2c3SDag-Erling Smørgrav struct addrinfo hints, *ailist, *ai;
9863fc9e2c3SDag-Erling Smørgrav ldns_status status;
9873fc9e2c3SDag-Erling Smørgrav ldns_rdf *rdf;
9883fc9e2c3SDag-Erling Smørgrav int err;
9893fc9e2c3SDag-Erling Smørgrav
9903fc9e2c3SDag-Erling Smørgrav memset(&hints, 0, sizeof hints);
9913fc9e2c3SDag-Erling Smørgrav switch (ldns_resolver_ip6(res)) {
9923fc9e2c3SDag-Erling Smørgrav case LDNS_RESOLV_INET: hints.ai_family = PF_INET; break;
9933fc9e2c3SDag-Erling Smørgrav case LDNS_RESOLV_INET6: hints.ai_family = PF_INET6; break;
9943fc9e2c3SDag-Erling Smørgrav default: hints.ai_family = PF_UNSPEC; break;
9953fc9e2c3SDag-Erling Smørgrav }
9963fc9e2c3SDag-Erling Smørgrav hints.ai_socktype = SOCK_STREAM;
9973fc9e2c3SDag-Erling Smørgrav do err = getaddrinfo(server, NULL, &hints, &ailist);
9983fc9e2c3SDag-Erling Smørgrav while (err == EAI_AGAIN);
9993fc9e2c3SDag-Erling Smørgrav if (err != 0)
10003fc9e2c3SDag-Erling Smørgrav die(1, "couldn't get address for '%s': %s", server, gai_strerror(err));
10013fc9e2c3SDag-Erling Smørgrav for (ai = ailist; ai != NULL; ai = ai->ai_next) {
10023fc9e2c3SDag-Erling Smørgrav if ((rdf = ldns_sockaddr_storage2rdf((void*)ai->ai_addr, NULL)) == NULL)
10033fc9e2c3SDag-Erling Smørgrav die(1, "couldn't allocate an rdf: %s",
10043fc9e2c3SDag-Erling Smørgrav ldns_get_errorstr_by_id(LDNS_STATUS_MEM_ERR));
10053fc9e2c3SDag-Erling Smørgrav status = ldns_resolver_push_nameserver(res, rdf);
10063fc9e2c3SDag-Erling Smørgrav if (status != LDNS_STATUS_OK)
10073fc9e2c3SDag-Erling Smørgrav die(1, "couldn't push a nameserver address: %s",
10083fc9e2c3SDag-Erling Smørgrav ldns_get_errorstr_by_id(status));
10093fc9e2c3SDag-Erling Smørgrav }
10103fc9e2c3SDag-Erling Smørgrav }
10113fc9e2c3SDag-Erling Smørgrav
10123fc9e2c3SDag-Erling Smørgrav static void
resolver_set_nameserver_str(ldns_resolver * res,const char * server)10133fc9e2c3SDag-Erling Smørgrav resolver_set_nameserver_str(ldns_resolver *res, const char *server) {
10143fc9e2c3SDag-Erling Smørgrav ldns_rdf *addr;
10153fc9e2c3SDag-Erling Smørgrav
10163fc9e2c3SDag-Erling Smørgrav ldns_resolver_remove_nameservers(res);
10173fc9e2c3SDag-Erling Smørgrav addr = ldns_rdf_new_addr_frm_str(server);
10183fc9e2c3SDag-Erling Smørgrav if (addr) {
10193fc9e2c3SDag-Erling Smørgrav if (ldns_resolver_push_nameserver(res, addr) != LDNS_STATUS_OK)
10203fc9e2c3SDag-Erling Smørgrav die(1, "couldn't push a nameserver address");
10213fc9e2c3SDag-Erling Smørgrav } else
10223fc9e2c3SDag-Erling Smørgrav resolver_set_nameserver_hostname(res, server);
10233fc9e2c3SDag-Erling Smørgrav }
10243fc9e2c3SDag-Erling Smørgrav
10253fc9e2c3SDag-Erling Smørgrav int
main(int argc,char * argv[])10263fc9e2c3SDag-Erling Smørgrav main(int argc, char *argv[]) {
10273fc9e2c3SDag-Erling Smørgrav ldns_rdf *addr, *dname;
10283fc9e2c3SDag-Erling Smørgrav ldns_resolver *res;
10293fc9e2c3SDag-Erling Smørgrav ldns_status status;
10303fc9e2c3SDag-Erling Smørgrav struct timeval restimeout;
10313fc9e2c3SDag-Erling Smørgrav
10323fc9e2c3SDag-Erling Smørgrav parse_args(argc, argv);
10333fc9e2c3SDag-Erling Smørgrav
10343fc9e2c3SDag-Erling Smørgrav status = ldns_resolver_new_default(&res);
10353fc9e2c3SDag-Erling Smørgrav if (status != LDNS_STATUS_OK)
10363fc9e2c3SDag-Erling Smørgrav die(1, "error creating resolver: %s", ldns_get_errorstr_by_id(status));
10373fc9e2c3SDag-Erling Smørgrav if (ldns_resolver_nameserver_count(res) == 0)
10383fc9e2c3SDag-Erling Smørgrav ldns_resolver_push_default_servers(res);
10393fc9e2c3SDag-Erling Smørgrav
10403fc9e2c3SDag-Erling Smørgrav ldns_resolver_set_usevc(res, o_tcp);
10413fc9e2c3SDag-Erling Smørgrav restimeout.tv_sec = o_timeout > 0 ? o_timeout :
10423fc9e2c3SDag-Erling Smørgrav o_tcp ? DEFAULT_TCP_TIMEOUT : DEFAULT_UDP_TIMEOUT;
10433fc9e2c3SDag-Erling Smørgrav restimeout.tv_usec = 0;
10443fc9e2c3SDag-Erling Smørgrav ldns_resolver_set_timeout(res, restimeout);
10453fc9e2c3SDag-Erling Smørgrav ldns_resolver_set_retry(res, o_retries+1);
10463fc9e2c3SDag-Erling Smørgrav ldns_resolver_set_ip6(res, o_ipversion);
10473fc9e2c3SDag-Erling Smørgrav ldns_resolver_set_defnames(res, false);
10483fc9e2c3SDag-Erling Smørgrav ldns_resolver_set_fallback(res, false);
10493fc9e2c3SDag-Erling Smørgrav
10503fc9e2c3SDag-Erling Smørgrav if (o_server)
10513fc9e2c3SDag-Erling Smørgrav resolver_set_nameserver_str(res, o_server);
10523fc9e2c3SDag-Erling Smørgrav
10533fc9e2c3SDag-Erling Smørgrav if (ldns_str2rdf_a(&addr, o_name) == LDNS_STATUS_OK) {
10543fc9e2c3SDag-Erling Smørgrav dname = ldns_rdf_reverse_a(addr, "in-addr.arpa");
10553fc9e2c3SDag-Erling Smørgrav if (dname == NULL)
10563fc9e2c3SDag-Erling Smørgrav die(1, "can't reverse '%s': %s", o_name,
10573fc9e2c3SDag-Erling Smørgrav ldns_get_errorstr_by_id(LDNS_STATUS_MEM_ERR));
10583fc9e2c3SDag-Erling Smørgrav o_mode = M_SINGLE_Q;
10593fc9e2c3SDag-Erling Smørgrav o_rrtype = LDNS_RR_TYPE_PTR;
10603fc9e2c3SDag-Erling Smørgrav return !doquery(res, dname);
10613fc9e2c3SDag-Erling Smørgrav } else if (ldns_str2rdf_aaaa(&addr, o_name) == LDNS_STATUS_OK) {
10623fc9e2c3SDag-Erling Smørgrav dname = ldns_rdf_reverse_aaaa(addr, o_ip6_int ? "ip6.int" : "ip6.arpa");
10633fc9e2c3SDag-Erling Smørgrav if (dname == NULL)
10643fc9e2c3SDag-Erling Smørgrav die(1, "can't reverse '%s': %s", o_name,
10653fc9e2c3SDag-Erling Smørgrav ldns_get_errorstr_by_id(LDNS_STATUS_MEM_ERR));
10663fc9e2c3SDag-Erling Smørgrav o_mode = M_SINGLE_Q;
10673fc9e2c3SDag-Erling Smørgrav o_rrtype = LDNS_RR_TYPE_PTR;
10683fc9e2c3SDag-Erling Smørgrav return !doquery(res, dname);
10693fc9e2c3SDag-Erling Smørgrav }
10703f68b24eSDag-Erling Smørgrav return !(o_mode == M_SOA ? dosoa :
10713f68b24eSDag-Erling Smørgrav o_mode == M_AXFR ? dozonetransfer :
10723f68b24eSDag-Erling Smørgrav o_mode == M_IXFR ? dozonetransfer :
10733f68b24eSDag-Erling Smørgrav dosearch)
10743fc9e2c3SDag-Erling Smørgrav (res, safe_str2rdf_dname(o_name), ndots(o_name) >= o_ndots);
10753fc9e2c3SDag-Erling Smørgrav }
1076