1*ce6743a3Snaddy /* $OpenBSD: res_query.c,v 1.4 2022/01/20 14:18:10 naddy Exp $ */
24c1e55dcSeric /*
34c1e55dcSeric * Copyright (c) 2012 Eric Faurot <eric@openbsd.org>
44c1e55dcSeric *
54c1e55dcSeric * Permission to use, copy, modify, and distribute this software for any
64c1e55dcSeric * purpose with or without fee is hereby granted, provided that the above
74c1e55dcSeric * copyright notice and this permission notice appear in all copies.
84c1e55dcSeric *
94c1e55dcSeric * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
104c1e55dcSeric * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
114c1e55dcSeric * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
124c1e55dcSeric * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
134c1e55dcSeric * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
144c1e55dcSeric * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
154c1e55dcSeric * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
164c1e55dcSeric */
174c1e55dcSeric
184c1e55dcSeric #include <sys/types.h>
194c1e55dcSeric #include <sys/socket.h>
2026c1daf0Seric #include <sys/time.h>
214c1e55dcSeric
224c1e55dcSeric #include <netinet/in.h>
234c1e55dcSeric #include <arpa/nameser.h>
244c1e55dcSeric #include <arpa/inet.h>
254c1e55dcSeric
264c1e55dcSeric #include <err.h>
274c1e55dcSeric #include <errno.h>
284c1e55dcSeric #include <getopt.h>
294c1e55dcSeric #include <inttypes.h>
304c1e55dcSeric #include <resolv.h>
314c1e55dcSeric #include <stdio.h>
324c1e55dcSeric #include <stdlib.h>
334c1e55dcSeric #include <string.h>
344c1e55dcSeric
354c1e55dcSeric #include "common.h"
364c1e55dcSeric
374c1e55dcSeric /* in asr.c but we don't want them exposed right now */
384c1e55dcSeric static void dump_packet(const void *, size_t);
394c1e55dcSeric
404c1e55dcSeric static char *print_query(struct query *, char *, size_t);
414c1e55dcSeric static char *print_rr(struct rr *, char *, size_t);
424c1e55dcSeric static char *print_host(const struct sockaddr *, char *, size_t);
434c1e55dcSeric static char* print_dname(const char *, char *, size_t);
444c1e55dcSeric
454c1e55dcSeric
464c1e55dcSeric static int
msec(struct timeval start,struct timeval end)474c1e55dcSeric msec(struct timeval start, struct timeval end)
484c1e55dcSeric {
494c1e55dcSeric return (int)((end.tv_sec - start.tv_sec) * 1000
504c1e55dcSeric + (end.tv_usec - start.tv_usec) / 1000);
514c1e55dcSeric }
524c1e55dcSeric
534c1e55dcSeric static void
usage(void)544c1e55dcSeric usage(void)
554c1e55dcSeric {
564c1e55dcSeric extern const char * __progname;
574c1e55dcSeric
584c1e55dcSeric fprintf(stderr, "usage: %s [-deq] [-t type] [host...]\n",
594c1e55dcSeric __progname);
604c1e55dcSeric exit(1);
614c1e55dcSeric }
624c1e55dcSeric
634c1e55dcSeric int
main(int argc,char * argv[])644c1e55dcSeric main(int argc, char *argv[])
654c1e55dcSeric {
664c1e55dcSeric struct timeval start, end;
674c1e55dcSeric time_t when;
684c1e55dcSeric int ch, i, qflag, dflag, r;
694c1e55dcSeric uint16_t type = T_A;
704c1e55dcSeric char buf[1024], *host;
714c1e55dcSeric
724c1e55dcSeric dflag = 0;
734c1e55dcSeric qflag = 0;
744c1e55dcSeric
75a9e85050Seric while((ch = getopt(argc, argv, "R:deqt:")) != -1) {
764c1e55dcSeric switch(ch) {
77a9e85050Seric case 'R':
78a9e85050Seric parseresopt(optarg);
79a9e85050Seric break;
804c1e55dcSeric case 'd':
814c1e55dcSeric dflag = 1;
824c1e55dcSeric break;
834c1e55dcSeric case 'e':
844c1e55dcSeric long_err += 1;
854c1e55dcSeric break;
864c1e55dcSeric case 'q':
874c1e55dcSeric qflag = 1;
884c1e55dcSeric break;
894c1e55dcSeric case 't':
904c1e55dcSeric if ((type = strtotype(optarg)) == 0)
914c1e55dcSeric usage();
924c1e55dcSeric break;
934c1e55dcSeric default:
944c1e55dcSeric usage();
954c1e55dcSeric /* NOTREACHED */
964c1e55dcSeric }
974c1e55dcSeric }
984c1e55dcSeric argc -= optind;
994c1e55dcSeric argv += optind;
1004c1e55dcSeric
1014c1e55dcSeric for (i = 0; i < argc; i++) {
1024c1e55dcSeric
1034c1e55dcSeric if (i)
1044c1e55dcSeric printf("\n");
1054c1e55dcSeric
1064c1e55dcSeric printf("===> \"%s\"\n", argv[i]);
1074c1e55dcSeric host = gethostarg(argv[i]);
1084c1e55dcSeric
1094c1e55dcSeric errno = 0;
1104c1e55dcSeric h_errno = 0;
1114c1e55dcSeric gai_errno = 0;
1124c1e55dcSeric rrset_errno = 0;
1134c1e55dcSeric
1144c1e55dcSeric if (gettimeofday(&start, NULL) != 0)
1154c1e55dcSeric err(1, "gettimeofday");
1164c1e55dcSeric
1174c1e55dcSeric if (qflag)
1184c1e55dcSeric r = res_query(host, C_IN, type, buf, sizeof(buf));
1194c1e55dcSeric else
1204c1e55dcSeric r = res_search(host, C_IN, type, buf, sizeof(buf));
1214c1e55dcSeric
1224c1e55dcSeric if (gettimeofday(&end, NULL) != 0)
1234c1e55dcSeric err(1, "gettimeofday");
1244c1e55dcSeric
1254c1e55dcSeric if (r != -1) {
1264c1e55dcSeric dump_packet(buf, r);
1274c1e55dcSeric printf("\n");
1284c1e55dcSeric if (dflag) {
1294c1e55dcSeric printf(";; Query time: %d msec\n",
1304c1e55dcSeric msec(start, end));
1314c1e55dcSeric when = time(NULL);
1324c1e55dcSeric printf(";; WHEN: %s", ctime(&when));
1334c1e55dcSeric }
1344c1e55dcSeric printf(";; MSG SIZE rcvd: %i\n", r);
1354c1e55dcSeric }
1364c1e55dcSeric print_errors();
1374c1e55dcSeric }
1384c1e55dcSeric
1394c1e55dcSeric return (0);
1404c1e55dcSeric }
1414c1e55dcSeric
1424c1e55dcSeric #define OPCODE_SHIFT 11
1434c1e55dcSeric #define Z_SHIFT 4
1444c1e55dcSeric
1454c1e55dcSeric static char*
print_header(struct header * h,char * buf,size_t max)1464c1e55dcSeric print_header(struct header *h, char *buf, size_t max)
1474c1e55dcSeric {
1484c1e55dcSeric snprintf(buf, max,
1494c1e55dcSeric "id:0x.... %s op:%i %s %s %s %s z:%i r:%s qd:%i an:%i ns:%i ar:%i",
1504c1e55dcSeric (h->flags & QR_MASK) ? "QR":" ",
1514c1e55dcSeric (int)(OPCODE(h->flags) >> OPCODE_SHIFT),
1524c1e55dcSeric (h->flags & AA_MASK) ? "AA":" ",
1534c1e55dcSeric (h->flags & TC_MASK) ? "TC":" ",
1544c1e55dcSeric (h->flags & RD_MASK) ? "RD":" ",
1554c1e55dcSeric (h->flags & RA_MASK) ? "RA":" ",
1564c1e55dcSeric ((h->flags & Z_MASK) >> Z_SHIFT),
1574c1e55dcSeric rcodetostr(RCODE(h->flags)),
1584c1e55dcSeric h->qdcount, h->ancount, h->nscount, h->arcount);
1594c1e55dcSeric
1604c1e55dcSeric return buf;
1614c1e55dcSeric }
1624c1e55dcSeric
1634c1e55dcSeric static void
dump_packet(const void * data,size_t len)1644c1e55dcSeric dump_packet(const void *data, size_t len)
1654c1e55dcSeric {
1664c1e55dcSeric char buf[1024];
1674c1e55dcSeric struct packed p;
1684c1e55dcSeric struct header h;
1694c1e55dcSeric struct query q;
1704c1e55dcSeric struct rr rr;
1714c1e55dcSeric int i, an, ns, ar, n;
1724c1e55dcSeric
1734c1e55dcSeric packed_init(&p, (char *)data, len);
1744c1e55dcSeric
1754c1e55dcSeric if (unpack_header(&p, &h) == -1) {
1764c1e55dcSeric printf(";; BAD PACKET: %s\n", p.err);
1774c1e55dcSeric return;
1784c1e55dcSeric }
1794c1e55dcSeric
1804c1e55dcSeric printf(";; HEADER %s\n", print_header(&h, buf, sizeof buf));
1814c1e55dcSeric
1824c1e55dcSeric if (h.qdcount)
1834c1e55dcSeric printf(";; QUERY SECTION:\n");
1844c1e55dcSeric for (i = 0; i < h.qdcount; i++) {
1854c1e55dcSeric if (unpack_query(&p, &q) == -1)
1864c1e55dcSeric goto error;
1874c1e55dcSeric printf("%s\n", print_query(&q, buf, sizeof buf));
1884c1e55dcSeric }
1894c1e55dcSeric
1904c1e55dcSeric an = 0;
1914c1e55dcSeric ns = an + h.ancount;
1924c1e55dcSeric ar = ns + h.nscount;
1934c1e55dcSeric n = ar + h.arcount;
1944c1e55dcSeric
1954c1e55dcSeric for (i = 0; i < n; i++) {
1964c1e55dcSeric if (i == an)
1974c1e55dcSeric printf("\n;; ANSWER SECTION:\n");
1984c1e55dcSeric if (i == ns)
1994c1e55dcSeric printf("\n;; AUTHORITY SECTION:\n");
2004c1e55dcSeric if (i == ar)
2014c1e55dcSeric printf("\n;; ADDITIONAL SECTION:\n");
2024c1e55dcSeric
2034c1e55dcSeric if (unpack_rr(&p, &rr) == -1)
2044c1e55dcSeric goto error;
2054c1e55dcSeric printf("%s\n", print_rr(&rr, buf, sizeof buf));
2064c1e55dcSeric }
2074c1e55dcSeric
2084c1e55dcSeric if (p.offset != len)
2094c1e55dcSeric printf(";; REMAINING GARBAGE %zu\n", len - p.offset);
2104c1e55dcSeric
2114c1e55dcSeric error:
2124c1e55dcSeric if (p.err)
2134c1e55dcSeric printf(";; ERROR AT OFFSET %zu/%zu: %s\n", p.offset, p.len,
2144c1e55dcSeric p.err);
2154c1e55dcSeric }
2164c1e55dcSeric
2174c1e55dcSeric static const char *
inet6_ntoa(struct in6_addr a)2184c1e55dcSeric inet6_ntoa(struct in6_addr a)
2194c1e55dcSeric {
2204c1e55dcSeric static char buf[256];
2214c1e55dcSeric struct sockaddr_in6 si;
2224c1e55dcSeric
2234c1e55dcSeric si.sin6_len = sizeof(si);
2244c1e55dcSeric si.sin6_family = PF_INET6;
2254c1e55dcSeric si.sin6_addr = a;
2264c1e55dcSeric
2274c1e55dcSeric return print_host((struct sockaddr*)&si, buf, sizeof buf);
2284c1e55dcSeric }
2294c1e55dcSeric
2304c1e55dcSeric static char*
print_rr(struct rr * rr,char * buf,size_t max)2314c1e55dcSeric print_rr(struct rr *rr, char *buf, size_t max)
2324c1e55dcSeric {
2334c1e55dcSeric char *res;
2344c1e55dcSeric char tmp[256];
2354c1e55dcSeric char tmp2[256];
2364c1e55dcSeric int r;
2374c1e55dcSeric
2384c1e55dcSeric res = buf;
2394c1e55dcSeric
2404c1e55dcSeric r = snprintf(buf, max, "%s %u %s %s ",
2414c1e55dcSeric print_dname(rr->rr_dname, tmp, sizeof tmp),
2424c1e55dcSeric rr->rr_ttl,
2434c1e55dcSeric classtostr(rr->rr_class),
2444c1e55dcSeric typetostr(rr->rr_type));
2454c1e55dcSeric if (r == -1) {
2464c1e55dcSeric buf[0] = '\0';
2474c1e55dcSeric return buf;
2484c1e55dcSeric }
2494c1e55dcSeric
2504c1e55dcSeric if ((size_t)r >= max)
2514c1e55dcSeric return buf;
2524c1e55dcSeric
2534c1e55dcSeric max -= r;
2544c1e55dcSeric buf += r;
2554c1e55dcSeric
2564c1e55dcSeric switch(rr->rr_type) {
2574c1e55dcSeric case T_CNAME:
2584c1e55dcSeric print_dname(rr->rr.cname.cname, buf, max);
2594c1e55dcSeric break;
2604c1e55dcSeric case T_MX:
2614c1e55dcSeric snprintf(buf, max, "%"PRIu32" %s",
2624c1e55dcSeric rr->rr.mx.preference,
2634c1e55dcSeric print_dname(rr->rr.mx.exchange, tmp, sizeof tmp));
2644c1e55dcSeric break;
2654c1e55dcSeric case T_NS:
2664c1e55dcSeric print_dname(rr->rr.ns.nsname, buf, max);
2674c1e55dcSeric break;
2684c1e55dcSeric case T_PTR:
2694c1e55dcSeric print_dname(rr->rr.ptr.ptrname, buf, max);
2704c1e55dcSeric break;
2714c1e55dcSeric case T_SOA:
2724c1e55dcSeric snprintf(buf, max,
2734c1e55dcSeric "%s %s %" PRIu32 " %" PRIu32 " %" PRIu32 " %" PRIu32 " %" PRIu32,
2744c1e55dcSeric print_dname(rr->rr.soa.rname, tmp, sizeof tmp),
2754c1e55dcSeric print_dname(rr->rr.soa.mname, tmp2, sizeof tmp2),
2764c1e55dcSeric rr->rr.soa.serial,
2774c1e55dcSeric rr->rr.soa.refresh,
2784c1e55dcSeric rr->rr.soa.retry,
2794c1e55dcSeric rr->rr.soa.expire,
2804c1e55dcSeric rr->rr.soa.minimum);
2814c1e55dcSeric break;
2824c1e55dcSeric case T_A:
2834c1e55dcSeric if (rr->rr_class != C_IN)
2844c1e55dcSeric goto other;
2854c1e55dcSeric snprintf(buf, max, "%s", inet_ntoa(rr->rr.in_a.addr));
2864c1e55dcSeric break;
2874c1e55dcSeric case T_AAAA:
2884c1e55dcSeric if (rr->rr_class != C_IN)
2894c1e55dcSeric goto other;
2904c1e55dcSeric snprintf(buf, max, "%s", inet6_ntoa(rr->rr.in_aaaa.addr6));
2914c1e55dcSeric break;
2924c1e55dcSeric default:
2934c1e55dcSeric other:
2944c1e55dcSeric snprintf(buf, max, "(rdlen=%"PRIu16 ")", rr->rr.other.rdlen);
2954c1e55dcSeric break;
2964c1e55dcSeric }
2974c1e55dcSeric
2984c1e55dcSeric return (res);
2994c1e55dcSeric }
3004c1e55dcSeric
3014c1e55dcSeric static char*
print_query(struct query * q,char * buf,size_t max)3024c1e55dcSeric print_query(struct query *q, char *buf, size_t max)
3034c1e55dcSeric {
3044c1e55dcSeric char b[256];
3054c1e55dcSeric
3064c1e55dcSeric snprintf(buf, max, "%s %s %s",
3074c1e55dcSeric print_dname(q->q_dname, b, sizeof b),
3084c1e55dcSeric classtostr(q->q_class), typetostr(q->q_type));
3094c1e55dcSeric
3104c1e55dcSeric return (buf);
3114c1e55dcSeric }
3124c1e55dcSeric
3134c1e55dcSeric
3144c1e55dcSeric static char *
print_host(const struct sockaddr * sa,char * buf,size_t len)3154c1e55dcSeric print_host(const struct sockaddr *sa, char *buf, size_t len)
3164c1e55dcSeric {
3174c1e55dcSeric switch (sa->sa_family) {
3184c1e55dcSeric case AF_INET:
3194c1e55dcSeric inet_ntop(AF_INET, &((struct sockaddr_in*)sa)->sin_addr, buf, len);
3204c1e55dcSeric break;
3214c1e55dcSeric case AF_INET6:
3224c1e55dcSeric inet_ntop(AF_INET6, &((struct sockaddr_in6*)sa)->sin6_addr, buf, len);
3234c1e55dcSeric break;
3244c1e55dcSeric default:
3254c1e55dcSeric buf[0] = '\0';
3264c1e55dcSeric }
3274c1e55dcSeric return (buf);
3284c1e55dcSeric }
3294c1e55dcSeric
3304c1e55dcSeric static char*
print_dname(const char * _dname,char * buf,size_t max)3314c1e55dcSeric print_dname(const char *_dname, char *buf, size_t max)
3324c1e55dcSeric {
3334c1e55dcSeric const unsigned char *dname = _dname;
3344c1e55dcSeric char *res;
335*ce6743a3Snaddy size_t left, count;
3364c1e55dcSeric
3374c1e55dcSeric if (_dname[0] == 0) {
3384c1e55dcSeric strlcpy(buf, ".", max);
3394c1e55dcSeric return buf;
3404c1e55dcSeric }
3414c1e55dcSeric
3424c1e55dcSeric res = buf;
3434c1e55dcSeric left = max - 1;
344*ce6743a3Snaddy while (dname[0] && left) {
3454c1e55dcSeric count = (dname[0] < (left - 1)) ? dname[0] : (left - 1);
3464c1e55dcSeric memmove(buf, dname + 1, count);
3474c1e55dcSeric dname += dname[0] + 1;
3484c1e55dcSeric left -= count;
3494c1e55dcSeric buf += count;
3504c1e55dcSeric if (left) {
3514c1e55dcSeric left -= 1;
3524c1e55dcSeric *buf++ = '.';
3534c1e55dcSeric }
3544c1e55dcSeric }
3554c1e55dcSeric buf[0] = 0;
3564c1e55dcSeric
3574c1e55dcSeric return (res);
3584c1e55dcSeric }
359