xref: /openbsd-src/regress/lib/libc/asr/bin/res_mkquery.c (revision ce6743a3b05387e650bcbabf73c82d33d634a9dc)
1*ce6743a3Snaddy /*	$OpenBSD: res_mkquery.c,v 1.3 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>
204c1e55dcSeric 
214c1e55dcSeric #include <netinet/in.h>
224c1e55dcSeric #include <arpa/nameser.h>
234c1e55dcSeric #include <arpa/inet.h>
244c1e55dcSeric 
254c1e55dcSeric #include <err.h>
264c1e55dcSeric #include <errno.h>
274c1e55dcSeric #include <getopt.h>
284c1e55dcSeric #include <inttypes.h>
294c1e55dcSeric #include <resolv.h>
304c1e55dcSeric #include <stdio.h>
314c1e55dcSeric #include <stdlib.h>
324c1e55dcSeric #include <string.h>
334c1e55dcSeric 
344c1e55dcSeric #include "common.h"
354c1e55dcSeric 
364c1e55dcSeric /* in asr.c but we don't want them exposed right now */
374c1e55dcSeric static void dump_packet(const void *, size_t);
384c1e55dcSeric 
394c1e55dcSeric static char *print_query(struct query *, char *, size_t);
404c1e55dcSeric static char *print_rr(struct rr *, char *, size_t);
414c1e55dcSeric static char *print_host(const struct sockaddr *, char *, size_t);
424c1e55dcSeric static char* print_dname(const char *, char *, size_t);
434c1e55dcSeric 
444c1e55dcSeric 
454c1e55dcSeric static void
usage(void)464c1e55dcSeric usage(void)
474c1e55dcSeric {
484c1e55dcSeric 	extern const char * __progname;
494c1e55dcSeric 
504c1e55dcSeric 	fprintf(stderr, "usage: %s [-deq] [-t type] [host...]\n",
514c1e55dcSeric 	    __progname);
524c1e55dcSeric 	exit(1);
534c1e55dcSeric }
544c1e55dcSeric 
554c1e55dcSeric int
main(int argc,char * argv[])564c1e55dcSeric main(int argc, char *argv[])
574c1e55dcSeric {
584c1e55dcSeric 	int			 ch, i, r;
594c1e55dcSeric 	uint16_t		 type = T_A;
604c1e55dcSeric 	char			 buf[1024], *host;
614c1e55dcSeric 
62a9e85050Seric 	while((ch = getopt(argc, argv, "R:et:")) !=  -1) {
634c1e55dcSeric 		switch(ch) {
64a9e85050Seric 		case 'R':
65a9e85050Seric 			parseresopt(optarg);
66a9e85050Seric 			break;
674c1e55dcSeric 		case 'e':
684c1e55dcSeric 			long_err += 1;
694c1e55dcSeric 			break;
704c1e55dcSeric 		case 't':
714c1e55dcSeric 			if ((type = strtotype(optarg)) == 0)
724c1e55dcSeric 				usage();
734c1e55dcSeric 			break;
744c1e55dcSeric 		default:
754c1e55dcSeric 			usage();
764c1e55dcSeric 			/* NOTREACHED */
774c1e55dcSeric 		}
784c1e55dcSeric 	}
794c1e55dcSeric 	argc -= optind;
804c1e55dcSeric 	argv += optind;
814c1e55dcSeric 
824c1e55dcSeric 	for (i = 0; i < argc; i++) {
834c1e55dcSeric 
844c1e55dcSeric 		if (i)
854c1e55dcSeric 			printf("\n");
864c1e55dcSeric 
874c1e55dcSeric 		printf("===> \"%s\"\n", argv[i]);
884c1e55dcSeric 		host = gethostarg(argv[i]);
894c1e55dcSeric 
904c1e55dcSeric 		errno = 0;
914c1e55dcSeric 		h_errno = 0;
924c1e55dcSeric 		gai_errno = 0;
934c1e55dcSeric 		rrset_errno = 0;
944c1e55dcSeric 
954c1e55dcSeric 		r = res_mkquery(QUERY, host, C_IN, type, NULL, 0, NULL, buf, sizeof(buf));
964c1e55dcSeric 		if (r != -1) {
974c1e55dcSeric 			dump_packet(buf, r);
984c1e55dcSeric 			printf(";; MSG SIZE %i\n", r);
994c1e55dcSeric 		}
1004c1e55dcSeric 		print_errors();
1014c1e55dcSeric 	}
1024c1e55dcSeric 
1034c1e55dcSeric 	return (0);
1044c1e55dcSeric }
1054c1e55dcSeric 
1064c1e55dcSeric #define OPCODE_SHIFT	11
1074c1e55dcSeric #define Z_SHIFT		4
1084c1e55dcSeric 
1094c1e55dcSeric static char*
print_header(struct header * h,char * buf,size_t max)1104c1e55dcSeric print_header(struct header *h, char *buf, size_t max)
1114c1e55dcSeric {
1124c1e55dcSeric 	snprintf(buf, max,
1134c1e55dcSeric 	"id:0x.... %s op:%i %s %s %s %s z:%i r:%s qd:%i an:%i ns:%i ar:%i",
1144c1e55dcSeric 	    (h->flags & QR_MASK) ? "QR":"  ",
1154c1e55dcSeric 	    (int)(OPCODE(h->flags) >> OPCODE_SHIFT),
1164c1e55dcSeric 	    (h->flags & AA_MASK) ? "AA":"  ",
1174c1e55dcSeric 	    (h->flags & TC_MASK) ? "TC":"  ",
1184c1e55dcSeric 	    (h->flags & RD_MASK) ? "RD":"  ",
1194c1e55dcSeric 	    (h->flags & RA_MASK) ? "RA":"  ",
1204c1e55dcSeric 	    ((h->flags & Z_MASK) >> Z_SHIFT),
1214c1e55dcSeric 	    rcodetostr(RCODE(h->flags)),
1224c1e55dcSeric 	    h->qdcount, h->ancount, h->nscount, h->arcount);
1234c1e55dcSeric 
1244c1e55dcSeric 	return buf;
1254c1e55dcSeric }
1264c1e55dcSeric 
1274c1e55dcSeric static void
dump_packet(const void * data,size_t len)1284c1e55dcSeric dump_packet(const void *data, size_t len)
1294c1e55dcSeric {
1304c1e55dcSeric 	char		buf[1024];
1314c1e55dcSeric 	struct packed	p;
1324c1e55dcSeric 	struct header	h;
1334c1e55dcSeric 	struct query	q;
1344c1e55dcSeric 	struct rr	rr;
1354c1e55dcSeric 	int		i, an, ns, ar, n;
1364c1e55dcSeric 
1374c1e55dcSeric 	packed_init(&p, (char *)data, len);
1384c1e55dcSeric 
1394c1e55dcSeric 	if (unpack_header(&p, &h) == -1) {
1404c1e55dcSeric 		printf(";; BAD PACKET: %s\n", p.err);
1414c1e55dcSeric 		return;
1424c1e55dcSeric 	}
1434c1e55dcSeric 
1444c1e55dcSeric 	printf(";; HEADER %s\n", print_header(&h, buf, sizeof buf));
1454c1e55dcSeric 
1464c1e55dcSeric 	if (h.qdcount)
1474c1e55dcSeric 		printf(";; QUERY SECTION:\n");
1484c1e55dcSeric 	for (i = 0; i < h.qdcount; i++) {
1494c1e55dcSeric 		if (unpack_query(&p, &q) == -1)
1504c1e55dcSeric 			goto error;
1514c1e55dcSeric 		printf("%s\n", print_query(&q, buf, sizeof buf));
1524c1e55dcSeric 	}
1534c1e55dcSeric 
1544c1e55dcSeric 	an = 0;
1554c1e55dcSeric 	ns = an + h.ancount;
1564c1e55dcSeric 	ar = ns + h.nscount;
1574c1e55dcSeric 	n = ar + h.arcount;
1584c1e55dcSeric 
1594c1e55dcSeric 	for (i = 0; i < n; i++) {
1604c1e55dcSeric 		if (i == an)
1614c1e55dcSeric 			printf("\n;; ANSWER SECTION:\n");
1624c1e55dcSeric 		if (i == ns)
1634c1e55dcSeric 			printf("\n;; AUTHORITY SECTION:\n");
1644c1e55dcSeric 		if (i == ar)
1654c1e55dcSeric 			printf("\n;; ADDITIONAL SECTION:\n");
1664c1e55dcSeric 
1674c1e55dcSeric 		if (unpack_rr(&p, &rr) == -1)
1684c1e55dcSeric 			goto error;
1694c1e55dcSeric 		printf("%s\n", print_rr(&rr, buf, sizeof buf));
1704c1e55dcSeric 	}
1714c1e55dcSeric 
1724c1e55dcSeric 	if (p.offset != len)
1734c1e55dcSeric 		printf(";; REMAINING GARBAGE %zu\n", len - p.offset);
1744c1e55dcSeric 
1754c1e55dcSeric     error:
1764c1e55dcSeric 	if (p.err)
1774c1e55dcSeric 		printf(";; ERROR AT OFFSET %zu/%zu: %s\n", p.offset, p.len,
1784c1e55dcSeric 		    p.err);
1794c1e55dcSeric }
1804c1e55dcSeric 
1814c1e55dcSeric static const char *
inet6_ntoa(struct in6_addr a)1824c1e55dcSeric inet6_ntoa(struct in6_addr a)
1834c1e55dcSeric {
1844c1e55dcSeric 	static char buf[256];
1854c1e55dcSeric 	struct sockaddr_in6	si;
1864c1e55dcSeric 
1874c1e55dcSeric 	si.sin6_len = sizeof(si);
1884c1e55dcSeric 	si.sin6_family = PF_INET6;
1894c1e55dcSeric 	si.sin6_addr = a;
1904c1e55dcSeric 
1914c1e55dcSeric 	return print_host((struct sockaddr*)&si, buf, sizeof buf);
1924c1e55dcSeric }
1934c1e55dcSeric 
1944c1e55dcSeric static char*
print_rr(struct rr * rr,char * buf,size_t max)1954c1e55dcSeric print_rr(struct rr *rr, char *buf, size_t max)
1964c1e55dcSeric {
1974c1e55dcSeric 	char	*res;
1984c1e55dcSeric 	char	 tmp[256];
1994c1e55dcSeric 	char	 tmp2[256];
2004c1e55dcSeric 	int	 r;
2014c1e55dcSeric 
2024c1e55dcSeric 	res = buf;
2034c1e55dcSeric 
2044c1e55dcSeric 	r = snprintf(buf, max, "%s %u %s %s ",
2054c1e55dcSeric 	    print_dname(rr->rr_dname, tmp, sizeof tmp),
2064c1e55dcSeric 	    rr->rr_ttl,
2074c1e55dcSeric 	    classtostr(rr->rr_class),
2084c1e55dcSeric 	    typetostr(rr->rr_type));
2094c1e55dcSeric 	if (r == -1) {
2104c1e55dcSeric 		buf[0] = '\0';
2114c1e55dcSeric 		return buf;
2124c1e55dcSeric 	}
2134c1e55dcSeric 
2144c1e55dcSeric 	if ((size_t)r >= max)
2154c1e55dcSeric 		return buf;
2164c1e55dcSeric 
2174c1e55dcSeric 	max -= r;
2184c1e55dcSeric 	buf += r;
2194c1e55dcSeric 
2204c1e55dcSeric 	switch(rr->rr_type) {
2214c1e55dcSeric 	case T_CNAME:
2224c1e55dcSeric 		print_dname(rr->rr.cname.cname, buf, max);
2234c1e55dcSeric 		break;
2244c1e55dcSeric 	case T_MX:
2254c1e55dcSeric 		snprintf(buf, max, "%"PRIu32" %s",
2264c1e55dcSeric 		    rr->rr.mx.preference,
2274c1e55dcSeric 		    print_dname(rr->rr.mx.exchange, tmp, sizeof tmp));
2284c1e55dcSeric 		break;
2294c1e55dcSeric 	case T_NS:
2304c1e55dcSeric 		print_dname(rr->rr.ns.nsname, buf, max);
2314c1e55dcSeric 		break;
2324c1e55dcSeric 	case T_PTR:
2334c1e55dcSeric 		print_dname(rr->rr.ptr.ptrname, buf, max);
2344c1e55dcSeric 		break;
2354c1e55dcSeric 	case T_SOA:
2364c1e55dcSeric 		snprintf(buf, max,
2374c1e55dcSeric 		    "%s %s %" PRIu32 " %" PRIu32 " %" PRIu32 " %" PRIu32 " %" PRIu32,
2384c1e55dcSeric 		    print_dname(rr->rr.soa.rname, tmp, sizeof tmp),
2394c1e55dcSeric 		    print_dname(rr->rr.soa.mname, tmp2, sizeof tmp2),
2404c1e55dcSeric 		    rr->rr.soa.serial,
2414c1e55dcSeric 		    rr->rr.soa.refresh,
2424c1e55dcSeric 		    rr->rr.soa.retry,
2434c1e55dcSeric 		    rr->rr.soa.expire,
2444c1e55dcSeric 		    rr->rr.soa.minimum);
2454c1e55dcSeric 		break;
2464c1e55dcSeric 	case T_A:
2474c1e55dcSeric 		if (rr->rr_class != C_IN)
2484c1e55dcSeric 			goto other;
2494c1e55dcSeric 		snprintf(buf, max, "%s", inet_ntoa(rr->rr.in_a.addr));
2504c1e55dcSeric 		break;
2514c1e55dcSeric 	case T_AAAA:
2524c1e55dcSeric 		if (rr->rr_class != C_IN)
2534c1e55dcSeric 			goto other;
2544c1e55dcSeric 		snprintf(buf, max, "%s", inet6_ntoa(rr->rr.in_aaaa.addr6));
2554c1e55dcSeric 		break;
2564c1e55dcSeric 	default:
2574c1e55dcSeric 	other:
2584c1e55dcSeric 		snprintf(buf, max, "(rdlen=%"PRIu16 ")", rr->rr.other.rdlen);
2594c1e55dcSeric 		break;
2604c1e55dcSeric 	}
2614c1e55dcSeric 
2624c1e55dcSeric 	return (res);
2634c1e55dcSeric }
2644c1e55dcSeric 
2654c1e55dcSeric static char*
print_query(struct query * q,char * buf,size_t max)2664c1e55dcSeric print_query(struct query *q, char *buf, size_t max)
2674c1e55dcSeric {
2684c1e55dcSeric 	char b[256];
2694c1e55dcSeric 
2704c1e55dcSeric 	snprintf(buf, max, "%s	%s %s",
2714c1e55dcSeric 	    print_dname(q->q_dname, b, sizeof b),
2724c1e55dcSeric 	    classtostr(q->q_class), typetostr(q->q_type));
2734c1e55dcSeric 
2744c1e55dcSeric 	return (buf);
2754c1e55dcSeric }
2764c1e55dcSeric 
2774c1e55dcSeric 
2784c1e55dcSeric static char *
print_host(const struct sockaddr * sa,char * buf,size_t len)2794c1e55dcSeric print_host(const struct sockaddr *sa, char *buf, size_t len)
2804c1e55dcSeric {
2814c1e55dcSeric 	switch (sa->sa_family) {
2824c1e55dcSeric 	case AF_INET:
2834c1e55dcSeric 		inet_ntop(AF_INET, &((struct sockaddr_in*)sa)->sin_addr, buf, len);
2844c1e55dcSeric 		break;
2854c1e55dcSeric 	case AF_INET6:
2864c1e55dcSeric 		inet_ntop(AF_INET6, &((struct sockaddr_in6*)sa)->sin6_addr, buf, len);
2874c1e55dcSeric 		break;
2884c1e55dcSeric 	default:
2894c1e55dcSeric 		buf[0] = '\0';
2904c1e55dcSeric 	}
2914c1e55dcSeric 	return (buf);
2924c1e55dcSeric }
2934c1e55dcSeric 
2944c1e55dcSeric static char*
print_dname(const char * _dname,char * buf,size_t max)2954c1e55dcSeric print_dname(const char *_dname, char *buf, size_t max)
2964c1e55dcSeric {
2974c1e55dcSeric 	const unsigned char *dname = _dname;
2984c1e55dcSeric 	char	*res;
299*ce6743a3Snaddy 	size_t	 left, count;
3004c1e55dcSeric 
3014c1e55dcSeric 	if (_dname[0] == 0) {
3024c1e55dcSeric 		strlcpy(buf, ".", max);
3034c1e55dcSeric 		return buf;
3044c1e55dcSeric 	}
3054c1e55dcSeric 
3064c1e55dcSeric 	res = buf;
3074c1e55dcSeric 	left = max - 1;
308*ce6743a3Snaddy 	while (dname[0] && left) {
3094c1e55dcSeric 		count = (dname[0] < (left - 1)) ? dname[0] : (left - 1);
3104c1e55dcSeric 		memmove(buf, dname + 1, count);
3114c1e55dcSeric 		dname += dname[0] + 1;
3124c1e55dcSeric 		left -= count;
3134c1e55dcSeric 		buf += count;
3144c1e55dcSeric 		if (left) {
3154c1e55dcSeric 			left -= 1;
3164c1e55dcSeric 			*buf++ = '.';
3174c1e55dcSeric 		}
3184c1e55dcSeric 	}
3194c1e55dcSeric 	buf[0] = 0;
3204c1e55dcSeric 
3214c1e55dcSeric 	return (res);
3224c1e55dcSeric }
323