xref: /openbsd-src/regress/lib/libc/asr/bin/res_query.c (revision ce6743a3b05387e650bcbabf73c82d33d634a9dc)
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