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