1 /* $OpenBSD: res_query.c,v 1.4 2022/01/20 14:18:10 naddy Exp $ */ 2 /* 3 * Copyright (c) 2012 Eric Faurot <eric@openbsd.org> 4 * 5 * Permission to use, copy, modify, and distribute this software for any 6 * purpose with or without fee is hereby granted, provided that the above 7 * copyright notice and this permission notice appear in all copies. 8 * 9 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 10 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 11 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 12 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 13 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 14 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 15 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 16 */ 17 18 #include <sys/types.h> 19 #include <sys/socket.h> 20 #include <sys/time.h> 21 22 #include <netinet/in.h> 23 #include <arpa/nameser.h> 24 #include <arpa/inet.h> 25 26 #include <err.h> 27 #include <errno.h> 28 #include <getopt.h> 29 #include <inttypes.h> 30 #include <resolv.h> 31 #include <stdio.h> 32 #include <stdlib.h> 33 #include <string.h> 34 35 #include "common.h" 36 37 /* in asr.c but we don't want them exposed right now */ 38 static void dump_packet(const void *, size_t); 39 40 static char *print_query(struct query *, char *, size_t); 41 static char *print_rr(struct rr *, char *, size_t); 42 static char *print_host(const struct sockaddr *, char *, size_t); 43 static char* print_dname(const char *, char *, size_t); 44 45 46 static int 47 msec(struct timeval start, struct timeval end) 48 { 49 return (int)((end.tv_sec - start.tv_sec) * 1000 50 + (end.tv_usec - start.tv_usec) / 1000); 51 } 52 53 static void 54 usage(void) 55 { 56 extern const char * __progname; 57 58 fprintf(stderr, "usage: %s [-deq] [-t type] [host...]\n", 59 __progname); 60 exit(1); 61 } 62 63 int 64 main(int argc, char *argv[]) 65 { 66 struct timeval start, end; 67 time_t when; 68 int ch, i, qflag, dflag, r; 69 uint16_t type = T_A; 70 char buf[1024], *host; 71 72 dflag = 0; 73 qflag = 0; 74 75 while((ch = getopt(argc, argv, "R:deqt:")) != -1) { 76 switch(ch) { 77 case 'R': 78 parseresopt(optarg); 79 break; 80 case 'd': 81 dflag = 1; 82 break; 83 case 'e': 84 long_err += 1; 85 break; 86 case 'q': 87 qflag = 1; 88 break; 89 case 't': 90 if ((type = strtotype(optarg)) == 0) 91 usage(); 92 break; 93 default: 94 usage(); 95 /* NOTREACHED */ 96 } 97 } 98 argc -= optind; 99 argv += optind; 100 101 for (i = 0; i < argc; i++) { 102 103 if (i) 104 printf("\n"); 105 106 printf("===> \"%s\"\n", argv[i]); 107 host = gethostarg(argv[i]); 108 109 errno = 0; 110 h_errno = 0; 111 gai_errno = 0; 112 rrset_errno = 0; 113 114 if (gettimeofday(&start, NULL) != 0) 115 err(1, "gettimeofday"); 116 117 if (qflag) 118 r = res_query(host, C_IN, type, buf, sizeof(buf)); 119 else 120 r = res_search(host, C_IN, type, buf, sizeof(buf)); 121 122 if (gettimeofday(&end, NULL) != 0) 123 err(1, "gettimeofday"); 124 125 if (r != -1) { 126 dump_packet(buf, r); 127 printf("\n"); 128 if (dflag) { 129 printf(";; Query time: %d msec\n", 130 msec(start, end)); 131 when = time(NULL); 132 printf(";; WHEN: %s", ctime(&when)); 133 } 134 printf(";; MSG SIZE rcvd: %i\n", r); 135 } 136 print_errors(); 137 } 138 139 return (0); 140 } 141 142 #define OPCODE_SHIFT 11 143 #define Z_SHIFT 4 144 145 static char* 146 print_header(struct header *h, char *buf, size_t max) 147 { 148 snprintf(buf, max, 149 "id:0x.... %s op:%i %s %s %s %s z:%i r:%s qd:%i an:%i ns:%i ar:%i", 150 (h->flags & QR_MASK) ? "QR":" ", 151 (int)(OPCODE(h->flags) >> OPCODE_SHIFT), 152 (h->flags & AA_MASK) ? "AA":" ", 153 (h->flags & TC_MASK) ? "TC":" ", 154 (h->flags & RD_MASK) ? "RD":" ", 155 (h->flags & RA_MASK) ? "RA":" ", 156 ((h->flags & Z_MASK) >> Z_SHIFT), 157 rcodetostr(RCODE(h->flags)), 158 h->qdcount, h->ancount, h->nscount, h->arcount); 159 160 return buf; 161 } 162 163 static void 164 dump_packet(const void *data, size_t len) 165 { 166 char buf[1024]; 167 struct packed p; 168 struct header h; 169 struct query q; 170 struct rr rr; 171 int i, an, ns, ar, n; 172 173 packed_init(&p, (char *)data, len); 174 175 if (unpack_header(&p, &h) == -1) { 176 printf(";; BAD PACKET: %s\n", p.err); 177 return; 178 } 179 180 printf(";; HEADER %s\n", print_header(&h, buf, sizeof buf)); 181 182 if (h.qdcount) 183 printf(";; QUERY SECTION:\n"); 184 for (i = 0; i < h.qdcount; i++) { 185 if (unpack_query(&p, &q) == -1) 186 goto error; 187 printf("%s\n", print_query(&q, buf, sizeof buf)); 188 } 189 190 an = 0; 191 ns = an + h.ancount; 192 ar = ns + h.nscount; 193 n = ar + h.arcount; 194 195 for (i = 0; i < n; i++) { 196 if (i == an) 197 printf("\n;; ANSWER SECTION:\n"); 198 if (i == ns) 199 printf("\n;; AUTHORITY SECTION:\n"); 200 if (i == ar) 201 printf("\n;; ADDITIONAL SECTION:\n"); 202 203 if (unpack_rr(&p, &rr) == -1) 204 goto error; 205 printf("%s\n", print_rr(&rr, buf, sizeof buf)); 206 } 207 208 if (p.offset != len) 209 printf(";; REMAINING GARBAGE %zu\n", len - p.offset); 210 211 error: 212 if (p.err) 213 printf(";; ERROR AT OFFSET %zu/%zu: %s\n", p.offset, p.len, 214 p.err); 215 } 216 217 static const char * 218 inet6_ntoa(struct in6_addr a) 219 { 220 static char buf[256]; 221 struct sockaddr_in6 si; 222 223 si.sin6_len = sizeof(si); 224 si.sin6_family = PF_INET6; 225 si.sin6_addr = a; 226 227 return print_host((struct sockaddr*)&si, buf, sizeof buf); 228 } 229 230 static char* 231 print_rr(struct rr *rr, char *buf, size_t max) 232 { 233 char *res; 234 char tmp[256]; 235 char tmp2[256]; 236 int r; 237 238 res = buf; 239 240 r = snprintf(buf, max, "%s %u %s %s ", 241 print_dname(rr->rr_dname, tmp, sizeof tmp), 242 rr->rr_ttl, 243 classtostr(rr->rr_class), 244 typetostr(rr->rr_type)); 245 if (r == -1) { 246 buf[0] = '\0'; 247 return buf; 248 } 249 250 if ((size_t)r >= max) 251 return buf; 252 253 max -= r; 254 buf += r; 255 256 switch(rr->rr_type) { 257 case T_CNAME: 258 print_dname(rr->rr.cname.cname, buf, max); 259 break; 260 case T_MX: 261 snprintf(buf, max, "%"PRIu32" %s", 262 rr->rr.mx.preference, 263 print_dname(rr->rr.mx.exchange, tmp, sizeof tmp)); 264 break; 265 case T_NS: 266 print_dname(rr->rr.ns.nsname, buf, max); 267 break; 268 case T_PTR: 269 print_dname(rr->rr.ptr.ptrname, buf, max); 270 break; 271 case T_SOA: 272 snprintf(buf, max, 273 "%s %s %" PRIu32 " %" PRIu32 " %" PRIu32 " %" PRIu32 " %" PRIu32, 274 print_dname(rr->rr.soa.rname, tmp, sizeof tmp), 275 print_dname(rr->rr.soa.mname, tmp2, sizeof tmp2), 276 rr->rr.soa.serial, 277 rr->rr.soa.refresh, 278 rr->rr.soa.retry, 279 rr->rr.soa.expire, 280 rr->rr.soa.minimum); 281 break; 282 case T_A: 283 if (rr->rr_class != C_IN) 284 goto other; 285 snprintf(buf, max, "%s", inet_ntoa(rr->rr.in_a.addr)); 286 break; 287 case T_AAAA: 288 if (rr->rr_class != C_IN) 289 goto other; 290 snprintf(buf, max, "%s", inet6_ntoa(rr->rr.in_aaaa.addr6)); 291 break; 292 default: 293 other: 294 snprintf(buf, max, "(rdlen=%"PRIu16 ")", rr->rr.other.rdlen); 295 break; 296 } 297 298 return (res); 299 } 300 301 static char* 302 print_query(struct query *q, char *buf, size_t max) 303 { 304 char b[256]; 305 306 snprintf(buf, max, "%s %s %s", 307 print_dname(q->q_dname, b, sizeof b), 308 classtostr(q->q_class), typetostr(q->q_type)); 309 310 return (buf); 311 } 312 313 314 static char * 315 print_host(const struct sockaddr *sa, char *buf, size_t len) 316 { 317 switch (sa->sa_family) { 318 case AF_INET: 319 inet_ntop(AF_INET, &((struct sockaddr_in*)sa)->sin_addr, buf, len); 320 break; 321 case AF_INET6: 322 inet_ntop(AF_INET6, &((struct sockaddr_in6*)sa)->sin6_addr, buf, len); 323 break; 324 default: 325 buf[0] = '\0'; 326 } 327 return (buf); 328 } 329 330 static char* 331 print_dname(const char *_dname, char *buf, size_t max) 332 { 333 const unsigned char *dname = _dname; 334 char *res; 335 size_t left, count; 336 337 if (_dname[0] == 0) { 338 strlcpy(buf, ".", max); 339 return buf; 340 } 341 342 res = buf; 343 left = max - 1; 344 while (dname[0] && left) { 345 count = (dname[0] < (left - 1)) ? dname[0] : (left - 1); 346 memmove(buf, dname + 1, count); 347 dname += dname[0] + 1; 348 left -= count; 349 buf += count; 350 if (left) { 351 left -= 1; 352 *buf++ = '.'; 353 } 354 } 355 buf[0] = 0; 356 357 return (res); 358 } 359