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