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