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