| 1 |
/* $Id: dnsget.c,v 1.31 2007/01/08 01:14:44 mjt Exp $ |
|---|
| 2 |
simple host/dig-like application using UDNS library |
|---|
| 3 |
|
|---|
| 4 |
Copyright (C) 2005 Michael Tokarev <mjt@corpit.ru> |
|---|
| 5 |
This file is part of UDNS library, an async DNS stub resolver. |
|---|
| 6 |
|
|---|
| 7 |
This library is free software; you can redistribute it and/or |
|---|
| 8 |
modify it under the terms of the GNU Lesser General Public |
|---|
| 9 |
License as published by the Free Software Foundation; either |
|---|
| 10 |
version 2.1 of the License, or (at your option) any later version. |
|---|
| 11 |
|
|---|
| 12 |
This library is distributed in the hope that it will be useful, |
|---|
| 13 |
but WITHOUT ANY WARRANTY; without even the implied warranty of |
|---|
| 14 |
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
|---|
| 15 |
Lesser General Public License for more details. |
|---|
| 16 |
|
|---|
| 17 |
You should have received a copy of the GNU Lesser General Public |
|---|
| 18 |
License along with this library, in file named COPYING.LGPL; if not, |
|---|
| 19 |
write to the Free Software Foundation, Inc., 59 Temple Place, |
|---|
| 20 |
Suite 330, Boston, MA 02111-1307 USA |
|---|
| 21 |
|
|---|
| 22 |
*/ |
|---|
| 23 |
|
|---|
| 24 |
#ifdef HAVE_UDNS_CONFIG_H |
|---|
| 25 |
# include "udns_config.h" |
|---|
| 26 |
#endif |
|---|
| 27 |
#ifdef WINDOWS |
|---|
| 28 |
#include <windows.h> |
|---|
| 29 |
#include <winsock2.h> |
|---|
| 30 |
#else |
|---|
| 31 |
#include <sys/types.h> |
|---|
| 32 |
#include <sys/socket.h> |
|---|
| 33 |
#include <netinet/in.h> |
|---|
| 34 |
#include <sys/time.h> |
|---|
| 35 |
#include <unistd.h> |
|---|
| 36 |
#endif |
|---|
| 37 |
#include <time.h> |
|---|
| 38 |
#include <stdarg.h> |
|---|
| 39 |
#include <errno.h> |
|---|
| 40 |
#include <stdio.h> |
|---|
| 41 |
#include <stdlib.h> |
|---|
| 42 |
#include <string.h> |
|---|
| 43 |
#include "udns.h" |
|---|
| 44 |
|
|---|
| 45 |
#ifndef HAVE_GETOPT |
|---|
| 46 |
# include "getopt.c" |
|---|
| 47 |
#endif |
|---|
| 48 |
|
|---|
| 49 |
#ifndef AF_INET6 |
|---|
| 50 |
# define AF_INET6 10 |
|---|
| 51 |
#endif |
|---|
| 52 |
|
|---|
| 53 |
static char *progname; |
|---|
| 54 |
static int verbose = 1; |
|---|
| 55 |
static int errors; |
|---|
| 56 |
static int notfound; |
|---|
| 57 |
|
|---|
| 58 |
/* verbosity level: |
|---|
| 59 |
* <0 - bare result |
|---|
| 60 |
* 0 - bare result and error messages |
|---|
| 61 |
* 1 - readable result |
|---|
| 62 |
* 2 - received packet contents and `trying ...' stuff |
|---|
| 63 |
* 3 - sent and received packet contents |
|---|
| 64 |
*/ |
|---|
| 65 |
|
|---|
| 66 |
static void die(int errnum, const char *fmt, ...) { |
|---|
| 67 |
va_list ap; |
|---|
| 68 |
fprintf(stderr, "%s: ", progname); |
|---|
| 69 |
va_start(ap, fmt); vfprintf(stderr, fmt, ap); va_end(ap); |
|---|
| 70 |
if (errnum) fprintf(stderr, ": %s\n", strerror(errnum)); |
|---|
| 71 |
else putc('\n', stderr); |
|---|
| 72 |
fflush(stderr); |
|---|
| 73 |
exit(1); |
|---|
| 74 |
} |
|---|
| 75 |
|
|---|
| 76 |
static const char *dns_xntop(int af, const void *src) { |
|---|
| 77 |
static char buf[6*5+4*4]; |
|---|
| 78 |
return dns_ntop(af, src, buf, sizeof(buf)); |
|---|
| 79 |
} |
|---|
| 80 |
|
|---|
| 81 |
struct query { |
|---|
| 82 |
const char *name; /* original query string */ |
|---|
| 83 |
unsigned char *dn; /* the DN being looked up */ |
|---|
| 84 |
enum dns_type qtyp; /* type of the query */ |
|---|
| 85 |
}; |
|---|
| 86 |
|
|---|
| 87 |
static void query_free(struct query *q) { |
|---|
| 88 |
free(q->dn); |
|---|
| 89 |
free(q); |
|---|
| 90 |
} |
|---|
| 91 |
|
|---|
| 92 |
static struct query * |
|---|
| 93 |
query_new(const char *name, const unsigned char *dn, enum dns_type qtyp) { |
|---|
| 94 |
struct query *q = malloc(sizeof(*q)); |
|---|
| 95 |
unsigned l = dns_dnlen(dn); |
|---|
| 96 |
unsigned char *cdn = malloc(l); |
|---|
| 97 |
if (!q || !cdn) die(0, "out of memory"); |
|---|
| 98 |
memcpy(cdn, dn, l); |
|---|
| 99 |
q->name = name; |
|---|
| 100 |
q->dn = cdn; |
|---|
| 101 |
q->qtyp = qtyp; |
|---|
| 102 |
return q; |
|---|
| 103 |
} |
|---|
| 104 |
|
|---|
| 105 |
static enum dns_class qcls = DNS_C_IN; |
|---|
| 106 |
|
|---|
| 107 |
static void |
|---|
| 108 |
dnserror(struct query *q, int errnum) { |
|---|
| 109 |
if (verbose >= 0) |
|---|
| 110 |
fprintf(stderr, "%s: unable to lookup %s record for %s: %s\n", progname, |
|---|
| 111 |
dns_typename(q->qtyp), dns_dntosp(q->dn), dns_strerror(errnum)); |
|---|
| 112 |
if (errnum == DNS_E_NXDOMAIN || errnum == DNS_E_NODATA) |
|---|
| 113 |
++notfound; |
|---|
| 114 |
else |
|---|
| 115 |
++errors; |
|---|
| 116 |
query_free(q); |
|---|
| 117 |
} |
|---|
| 118 |
|
|---|
| 119 |
static const unsigned char * |
|---|
| 120 |
printtxt(const unsigned char *c) { |
|---|
| 121 |
unsigned n = *c++; |
|---|
| 122 |
const unsigned char *e = c + n; |
|---|
| 123 |
if (verbose > 0) while(c < e) { |
|---|
| 124 |
if (*c < ' ' || *c >= 127) printf("\\%02x", *c); |
|---|
| 125 |
else if (*c == '\\' || *c == '"') printf("\\%c", *c); |
|---|
| 126 |
else putchar(*c); |
|---|
| 127 |
++c; |
|---|
| 128 |
} |
|---|
| 129 |
else |
|---|
| 130 |
fwrite(c, n, 1, stdout); |
|---|
| 131 |
return e; |
|---|
| 132 |
} |
|---|
| 133 |
|
|---|
| 134 |
static void |
|---|
| 135 |
printhex(const unsigned char *c, const unsigned char *e) { |
|---|
| 136 |
while(c < e) |
|---|
| 137 |
printf("%02x", *c++); |
|---|
| 138 |
} |
|---|
| 139 |
|
|---|
| 140 |
static unsigned char to_b64[] = |
|---|
| 141 |
"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; |
|---|
| 142 |
|
|---|
| 143 |
static void |
|---|
| 144 |
printb64(const unsigned char *c, const unsigned char *e) { |
|---|
| 145 |
while(c < e) { |
|---|
| 146 |
putchar(to_b64[c[0] >> 2]); |
|---|
| 147 |
if (c+1 < e) { |
|---|
| 148 |
putchar(to_b64[(c[0] & 0x3) << 4 | c[1] >> 4]); |
|---|
| 149 |
if (c+2 < e) { |
|---|
| 150 |
putchar(to_b64[(c[1] & 0xf) << 2 | c[2] >> 6]); |
|---|
| 151 |
putchar(to_b64[c[2] & 0x3f]); |
|---|
| 152 |
} |
|---|
| 153 |
else { |
|---|
| 154 |
putchar(to_b64[(c[1] & 0xf) << 2]); |
|---|
| 155 |
putchar('='); |
|---|
| 156 |
break; |
|---|
| 157 |
} |
|---|
| 158 |
} |
|---|
| 159 |
else { |
|---|
| 160 |
putchar(to_b64[(c[0] & 0x3) << 4]); |
|---|
| 161 |
putchar('='); |
|---|
| 162 |
putchar('='); |
|---|
| 163 |
break; |
|---|
| 164 |
} |
|---|
| 165 |
c += 3; |
|---|
| 166 |
} |
|---|
| 167 |
} |
|---|
| 168 |
|
|---|
| 169 |
static void |
|---|
| 170 |
printdate(time_t time) { |
|---|
| 171 |
struct tm *tm = gmtime(&time); |
|---|
| 172 |
printf("%04d%02d%02d%02d%02d%02d", |
|---|
| 173 |
tm->tm_year + 1900, tm->tm_mon + 1, tm->tm_mday, |
|---|
| 174 |
tm->tm_hour, tm->tm_min, tm->tm_sec); |
|---|
| 175 |
} |
|---|
| 176 |
|
|---|
| 177 |
static void |
|---|
| 178 |
printrr(const struct dns_parse *p, struct dns_rr *rr) { |
|---|
| 179 |
const unsigned char *pkt = p->dnsp_pkt; |
|---|
| 180 |
const unsigned char *end = p->dnsp_end; |
|---|
| 181 |
const unsigned char *dptr = rr->dnsrr_dptr; |
|---|
| 182 |
const unsigned char *dend = rr->dnsrr_dend; |
|---|
| 183 |
unsigned char *dn = rr->dnsrr_dn; |
|---|
| 184 |
const unsigned char *c; |
|---|
| 185 |
unsigned n; |
|---|
| 186 |
|
|---|
| 187 |
if (verbose > 0) { |
|---|
| 188 |
if (verbose > 1) { |
|---|
| 189 |
if (!p->dnsp_rrl && !rr->dnsrr_dn[0] && rr->dnsrr_typ == DNS_T_OPT) { |
|---|
| 190 |
printf(";EDNS0 OPT record (UDPsize: %d): %d bytes\n", |
|---|
| 191 |
rr->dnsrr_cls, rr->dnsrr_dsz); |
|---|
| 192 |
return; |
|---|
| 193 |
} |
|---|
| 194 |
n = printf("%s.", dns_dntosp(rr->dnsrr_dn)); |
|---|
| 195 |
printf("%s%u\t%s\t%s\t", |
|---|
| 196 |
n > 15 ? "\t" : n > 7 ? "\t\t" : "\t\t\t", |
|---|
| 197 |
rr->dnsrr_ttl, |
|---|
| 198 |
dns_classname(rr->dnsrr_cls), |
|---|
| 199 |
dns_typename(rr->dnsrr_typ)); |
|---|
| 200 |
} |
|---|
| 201 |
else |
|---|
| 202 |
printf("%s. %s ", dns_dntosp(rr->dnsrr_dn), dns_typename(rr->dnsrr_typ)); |
|---|
| 203 |
} |
|---|
| 204 |
|
|---|
| 205 |
switch(rr->dnsrr_typ) { |
|---|
| 206 |
|
|---|
| 207 |
case DNS_T_CNAME: |
|---|
| 208 |
case DNS_T_PTR: |
|---|
| 209 |
case DNS_T_NS: |
|---|
| 210 |
case DNS_T_MB: |
|---|
| 211 |
case DNS_T_MD: |
|---|
| 212 |
case DNS_T_MF: |
|---|
| 213 |
case DNS_T_MG: |
|---|
| 214 |
case DNS_T_MR: |
|---|
| 215 |
if (dns_getdn(pkt, &dptr, end, dn, DNS_MAXDN) <= 0) goto xperr; |
|---|
| 216 |
printf("%s.", dns_dntosp(dn)); |
|---|
| 217 |
break; |
|---|
| 218 |
|
|---|
| 219 |
case DNS_T_A: |
|---|
| 220 |
if (rr->dnsrr_dsz != 4) goto xperr; |
|---|
| 221 |
printf("%d.%d.%d.%d", dptr[0], dptr[1], dptr[2], dptr[3]); |
|---|
| 222 |
break; |
|---|
| 223 |
|
|---|
| 224 |
case DNS_T_AAAA: |
|---|
| 225 |
if (rr->dnsrr_dsz != 16) goto xperr; |
|---|
| 226 |
printf("%s", dns_xntop(AF_INET6, dptr)); |
|---|
| 227 |
break; |
|---|
| 228 |
|
|---|
| 229 |
case DNS_T_MX: |
|---|
| 230 |
c = dptr + 2; |
|---|
| 231 |
if (dns_getdn(pkt, &c, end, dn, DNS_MAXDN) <= 0 || c != dend) goto xperr; |
|---|
| 232 |
printf("%d %s.", dns_get16(dptr), dns_dntosp(dn)); |
|---|
| 233 |
break; |
|---|
| 234 |
|
|---|
| 235 |
case DNS_T_TXT: |
|---|
| 236 |
/* first verify it */ |
|---|
| 237 |
for(c = dptr; c < dend; c += n) { |
|---|
| 238 |
n = *c++; |
|---|
| 239 |
if (c + n > dend) goto xperr; |
|---|
| 240 |
} |
|---|
| 241 |
c = dptr; n = 0; |
|---|
| 242 |
while (c < dend) { |
|---|
| 243 |
if (verbose > 0) printf(n++ ? "\" \"":"\""); |
|---|
| 244 |
c = printtxt(c); |
|---|
| 245 |
} |
|---|
| 246 |
if (verbose > 0) putchar('"'); |
|---|
| 247 |
break; |
|---|
| 248 |
|
|---|
| 249 |
case DNS_T_HINFO: /* CPU, OS */ |
|---|
| 250 |
c = dptr; |
|---|
| 251 |
n = *c++; if ((c += n) >= dend) goto xperr; |
|---|
| 252 |
n = *c++; if ((c += n) != dend) goto xperr; |
|---|
| 253 |
c = dptr; |
|---|
| 254 |
if (verbose > 0) putchar('"'); |
|---|
| 255 |
c = printtxt(c); |
|---|
| 256 |
if (verbose > 0) printf("\" \""); else putchar(' '); |
|---|
| 257 |
printtxt(c); |
|---|
| 258 |
if (verbose > 0) putchar('"'); |
|---|
| 259 |
break; |
|---|
| 260 |
|
|---|
| 261 |
case DNS_T_WKS: |
|---|
| 262 |
c = dptr; |
|---|
| 263 |
if (dptr + 4 + 2 >= end) goto xperr; |
|---|
| 264 |
printf("%s %d", dns_xntop(AF_INET, dptr), dptr[4]); |
|---|
| 265 |
c = dptr + 5; |
|---|
| 266 |
for (n = 0; c < dend; ++c, n += 8) { |
|---|
| 267 |
if (*c) { |
|---|
| 268 |
unsigned b; |
|---|
| 269 |
for (b = 0; b < 8; ++b) |
|---|
| 270 |
if (*c & (1 << (7-b))) printf(" %d", n + b); |
|---|
| 271 |
} |
|---|
| 272 |
} |
|---|
| 273 |
break; |
|---|
| 274 |
|
|---|
| 275 |
case DNS_T_SRV: /* prio weight port targetDN */ |
|---|
| 276 |
c = dptr; |
|---|
| 277 |
c += 2 + 2 + 2; |
|---|
| 278 |
if (dns_getdn(pkt, &c, end, dn, DNS_MAXDN) <= 0 || c != dend) goto xperr; |
|---|
| 279 |
c = dptr; |
|---|
| 280 |
printf("%d %d %d %s.", |
|---|
| 281 |
dns_get16(c+0), dns_get16(c+2), dns_get16(c+4), |
|---|
| 282 |
dns_dntosp(dn)); |
|---|
| 283 |
break; |
|---|
| 284 |
|
|---|
| 285 |
case DNS_T_NAPTR: /* order pref flags serv regexp repl */ |
|---|
| 286 |
c = dptr; |
|---|
| 287 |
c += 4; /* order, pref */ |
|---|
| 288 |
for (n = 0; n < 3; ++n) |
|---|
| 289 |
if (c >= dend) goto xperr; |
|---|
| 290 |
else c += *c + 1; |
|---|
| 291 |
if (dns_getdn(pkt, &c, end, dn, DNS_MAXDN) <= 0 || c != dend) goto xperr; |
|---|
| 292 |
c = dptr; |
|---|
| 293 |
printf("%u %u", dns_get16(c+0), dns_get16(c+2)); |
|---|
| 294 |
c += 4; |
|---|
| 295 |
for(n = 0; n < 3; ++n) { |
|---|
| 296 |
putchar(' '); |
|---|
| 297 |
if (verbose > 0) putchar('"'); |
|---|
| 298 |
c = printtxt(c); |
|---|
| 299 |
if (verbose > 0) putchar('"'); |
|---|
| 300 |
} |
|---|
| 301 |
printf(" %s.", dns_dntosp(dn)); |
|---|
| 302 |
break; |
|---|
| 303 |
|
|---|
| 304 |
case DNS_T_KEY: /* flags(2) proto(1) algo(1) pubkey */ |
|---|
| 305 |
c = dptr; |
|---|
| 306 |
if (c + 2 + 1 + 1 > dend) goto xperr; |
|---|
| 307 |
printf("%d %d %d", dns_get16(c), c[2], c[3]); |
|---|
| 308 |
c += 2 + 1 + 1; |
|---|
| 309 |
if (c < dend) { |
|---|
| 310 |
putchar(' '); |
|---|
| 311 |
printb64(c, dend); |
|---|
| 312 |
} |
|---|
| 313 |
break; |
|---|
| 314 |
|
|---|
| 315 |
case DNS_T_SIG: |
|---|
| 316 |
/* type(2) algo(1) labels(1) ottl(4) sexp(4) sinc(4) tag(2) sdn sig */ |
|---|
| 317 |
c = dptr; |
|---|
| 318 |
c += 2 + 1 + 1 + 4 + 4 + 4 + 2; |
|---|
| 319 |
if (dns_getdn(pkt, &c, end, dn, DNS_MAXDN) <= 0) goto xperr; |
|---|
| 320 |
printf("%d %u %u %u ", |
|---|
| 321 |
dns_get16(dptr), dptr[2], dptr[3], dns_get32(dptr+4)); |
|---|
| 322 |
printdate(dns_get32(dptr+8)); |
|---|
| 323 |
putchar(' '); |
|---|
| 324 |
printdate(dns_get32(dptr+12)); |
|---|
| 325 |
printf(" %d %s. ", dns_get16(dptr+10), dns_dntosp(dn)); |
|---|
| 326 |
printb64(c, dend); |
|---|
| 327 |
break; |
|---|
| 328 |
|
|---|
| 329 |
#if 0 /* unused RR types? */ |
|---|
| 330 |
case DNS_T_DS: |
|---|
| 331 |
c = dptr; |
|---|
| 332 |
if (c + 2 + 2 >= dend) goto xperr; |
|---|
| 333 |
printf("%u %u %u ", dns_get16(c), c[2], c[3]); |
|---|
| 334 |
printhex(c + 4, dend); |
|---|
| 335 |
break; |
|---|
| 336 |
|
|---|
| 337 |
case DNS_T_NSEC: |
|---|
| 338 |
c = dptr; |
|---|
| 339 |
if (dns_getdn(pkt, &c, end, dn, DNS_MAXDN) <= 0) goto xperr; |
|---|
| 340 |
printf("%s.", dns_dntosp(dn)); |
|---|
| 341 |
unfinished. |
|---|
| 342 |
break; |
|---|
| 343 |
#endif |
|---|
| 344 |
|
|---|
| 345 |
|
|---|
| 346 |
case DNS_T_SOA: |
|---|
| 347 |
c = dptr; |
|---|
| 348 |
if (dns_getdn(pkt, &c, end, dn, DNS_MAXDN) <= 0 || |
|---|
| 349 |
dns_getdn(pkt, &c, end, dn, DNS_MAXDN) <= 0 || |
|---|
| 350 |
c + 4*5 != dend) |
|---|
| 351 |
goto xperr; |
|---|
| 352 |
dns_getdn(pkt, &dptr, end, dn, DNS_MAXDN); |
|---|
| 353 |
printf("%s. ", dns_dntosp(dn)); |
|---|
| 354 |
dns_getdn(pkt, &dptr, end, dn, DNS_MAXDN); |
|---|
| 355 |
printf("%s. ", dns_dntosp(dn)); |
|---|
| 356 |
printf("%u %u %u %u %u", |
|---|
| 357 |
dns_get32(dptr), dns_get32(dptr+4), dns_get32(dptr+8), |
|---|
| 358 |
dns_get32(dptr+12), dns_get32(dptr+16)); |
|---|
| 359 |
break; |
|---|
| 360 |
|
|---|
| 361 |
case DNS_T_MINFO: |
|---|
| 362 |
c = dptr; |
|---|
| 363 |
if (dns_getdn(pkt, &c, end, dn, DNS_MAXDN) <= 0 || |
|---|
| 364 |
dns_getdn(pkt, &c, end, dn, DNS_MAXDN) <= 0 || |
|---|
| 365 |
c != dend) |
|---|
| 366 |
goto xperr; |
|---|
| 367 |
dns_getdn(pkt, &dptr, end, dn, DNS_MAXDN); |
|---|
| 368 |
printf("%s. ", dns_dntosp(dn)); |
|---|
| 369 |
dns_getdn(pkt, &dptr, end, dn, DNS_MAXDN); |
|---|
| 370 |
printf("%s.", dns_dntosp(dn)); |
|---|
| 371 |
break; |
|---|
| 372 |
|
|---|
| 373 |
case DNS_T_NULL: |
|---|
| 374 |
default: |
|---|
| 375 |
printhex(dptr, dend); |
|---|
| 376 |
break; |
|---|
| 377 |
} |
|---|
| 378 |
putchar('\n'); |
|---|
| 379 |
return; |
|---|
| 380 |
|
|---|
| 381 |
xperr: |
|---|
| 382 |
printf("<parse error>\n"); |
|---|
| 383 |
++errors; |
|---|
| 384 |
} |
|---|
| 385 |
|
|---|
| 386 |
static int |
|---|
| 387 |
printsection(struct dns_parse *p, int nrr, const char *sname) { |
|---|
| 388 |
struct dns_rr rr; |
|---|
| 389 |
int r; |
|---|
| 390 |
if (!nrr) return 0; |
|---|
| 391 |
if (verbose > 1) printf("\n;; %s section (%d):\n", sname, nrr); |
|---|
| 392 |
|
|---|
| 393 |
p->dnsp_rrl = nrr; |
|---|
| 394 |
while((r = dns_nextrr(p, &rr)) > 0) |
|---|
| 395 |
printrr(p, &rr); |
|---|
| 396 |
if (r < 0) printf("<<ERROR>>\n"); |
|---|
| 397 |
return r; |
|---|
| 398 |
} |
|---|
| 399 |
|
|---|
| 400 |
/* dbgcb will only be called if verbose > 1 */ |
|---|
| 401 |
static void |
|---|
| 402 |
dbgcb(int code, const struct sockaddr *sa, unsigned slen, |
|---|
| 403 |
const unsigned char *pkt, int r, |
|---|
| 404 |
const struct dns_query *unused_q, void *unused_data) { |
|---|
| 405 |
struct dns_parse p; |
|---|
| 406 |
const unsigned char *cur, *end; |
|---|
| 407 |
int numqd; |
|---|
| 408 |
|
|---|
| 409 |
if (code > 0) { |
|---|
| 410 |
printf(";; trying %s.\n", dns_dntosp(dns_payload(pkt))); |
|---|
| 411 |
printf(";; sending %d bytes query to ", r); |
|---|
| 412 |
} |
|---|
| 413 |
else |
|---|
| 414 |
printf(";; received %d bytes response from ", r); |
|---|
| 415 |
if (sa->sa_family == AF_INET && slen >= sizeof(struct sockaddr_in)) |
|---|
| 416 |
printf("%s port %d\n", |
|---|
| 417 |
dns_xntop(AF_INET, &((struct sockaddr_in*)sa)->sin_addr), |
|---|
| 418 |
htons(((struct sockaddr_in*)sa)->sin_port)); |
|---|
| 419 |
#ifdef HAVE_IPv6 |
|---|
| 420 |
else if (sa->sa_family == AF_INET6 && slen >= sizeof(struct sockaddr_in6)) |
|---|
| 421 |
printf("%s port %d\n", |
|---|
| 422 |
dns_xntop(AF_INET6, &((struct sockaddr_in6*)sa)->sin6_addr), |
|---|
| 423 |
htons(((struct sockaddr_in6*)sa)->sin6_port)); |
|---|
| 424 |
#endif |
|---|
| 425 |
else |
|---|
| 426 |
printf("<<unknown socket type %d>>\n", sa->sa_family); |
|---|
| 427 |
if (code > 0 && verbose < 3) { |
|---|
| 428 |
putchar('\n'); |
|---|
| 429 |
return; |
|---|
| 430 |
} |
|---|
| 431 |
|
|---|
| 432 |
if (code == -2) printf(";; reply from unexpected source\n"); |
|---|
| 433 |
if (code == -5) printf(";; reply to a query we didn't sent (or old)\n"); |
|---|
| 434 |
if (r < DNS_HSIZE) { |
|---|
| 435 |
printf(";; short packet (%d bytes)\n", r); |
|---|
| 436 |
return; |
|---|
| 437 |
} |
|---|
| 438 |
if (dns_opcode(pkt) != 0) |
|---|
| 439 |
printf(";; unexpected opcode %d\n", dns_opcode(pkt)); |
|---|
| 440 |
if (dns_tc(pkt) != 0) |
|---|
| 441 |
printf(";; warning: TC bit set, probably incomplete reply\n"); |
|---|
| 442 |
|
|---|
| 443 |
printf(";; ->>HEADER<<- opcode: "); |
|---|
| 444 |
switch(dns_opcode(pkt)) { |
|---|
| 445 |
case 0: printf("QUERY"); break; |
|---|
| 446 |
case 1: printf("IQUERY"); break; |
|---|
| 447 |
case 2: printf("STATUS"); break; |
|---|
| 448 |
default: printf("UNKNOWN(%u)", dns_opcode(pkt)); break; |
|---|
| 449 |
} |
|---|
| 450 |
printf(", status: %s, id: %d, size: %d\n;; flags:", |
|---|
| 451 |
dns_rcodename(dns_rcode(pkt)), dns_qid(pkt), r); |
|---|
| 452 |
if (dns_qr(pkt)) printf(" qr"); |
|---|
| 453 |
if (dns_rd(pkt)) printf(" rd"); |
|---|
| 454 |
if (dns_ra(pkt)) printf(" ra"); |
|---|
| 455 |
if (dns_aa(pkt)) printf(" aa"); |
|---|
| 456 |
if (dns_tc(pkt)) printf(" tc"); |
|---|
| 457 |
numqd = dns_numqd(pkt); |
|---|
| 458 |
printf("; QUERY: %d, ANSWER: %d, AUTHORITY: %d, ADDITIONAL: %d\n", |
|---|
| 459 |
numqd, dns_numan(pkt), dns_numns(pkt), dns_numar(pkt)); |
|---|
| 460 |
if (numqd != 1) |
|---|
| 461 |
printf(";; unexpected number of entries in QUERY section: %d\n", |
|---|
| 462 |
numqd); |
|---|
| 463 |
printf("\n;; QUERY SECTION (%d):\n", numqd); |
|---|
| 464 |
cur = dns_payload(pkt); |
|---|
| 465 |
end = pkt + r; |
|---|
| 466 |
while(numqd--) { |
|---|
| 467 |
if (dns_getdn(pkt, &cur, end, p.dnsp_dnbuf, DNS_MAXDN) <= 0 || |
|---|
| 468 |
cur + 4 > end) { |
|---|
| 469 |
printf("; invalid query section\n"); |
|---|
| 470 |
return; |
|---|
| 471 |
} |
|---|
| 472 |
r = printf(";%s.", dns_dntosp(p.dnsp_dnbuf)); |
|---|
| 473 |
printf("%s%s\t%s\n", |
|---|
| 474 |
r > 23 ? "\t" : r > 15 ? "\t\t" : r > 7 ? "\t\t\t" : "\t\t\t\t", |
|---|
| 475 |
dns_classname(dns_get16(cur+2)), dns_typename(dns_get16(cur))); |
|---|
| 476 |
cur += 4; |
|---|
| 477 |
} |
|---|
| 478 |
|
|---|
| 479 |
p.dnsp_pkt = pkt; |
|---|
| 480 |
p.dnsp_cur = p.dnsp_ans = cur; |
|---|
| 481 |
p.dnsp_end = end; |
|---|
| 482 |
p.dnsp_qdn = NULL; |
|---|
| 483 |
p.dnsp_qcls = p.dnsp_qtyp = 0; |
|---|
| 484 |
p.dnsp_ttl = 0xffffffffu; |
|---|
| 485 |
p.dnsp_nrr = 0; |
|---|
| 486 |
|
|---|
| 487 |
r = printsection(&p, dns_numan(pkt), "ANSWER"); |
|---|
| 488 |
if (r == 0) |
|---|
| 489 |
r = printsection(&p, dns_numns(pkt), "AUTHORITY"); |
|---|
| 490 |
if (r == 0) |
|---|
| 491 |
r = printsection(&p, dns_numar(pkt), "ADDITIONAL"); |
|---|
| 492 |
putchar('\n'); |
|---|
| 493 |
} |
|---|
| 494 |
|
|---|
| 495 |
static void dnscb(struct dns_ctx *ctx, void *result, void *data) { |
|---|
| 496 |
int r = dns_status(ctx); |
|---|
| 497 |
struct query *q = data; |
|---|
| 498 |
struct dns_parse p; |
|---|
| 499 |
struct dns_rr rr; |
|---|
| 500 |
unsigned nrr; |
|---|
| 501 |
unsigned char dn[DNS_MAXDN]; |
|---|
| 502 |
const unsigned char *pkt, *cur, *end; |
|---|
| 503 |
if (!result) { |
|---|
| 504 |
dnserror(q, r); |
|---|
| 505 |
return; |
|---|
| 506 |
} |
|---|
| 507 |
pkt = result; end = pkt + r; cur = dns_payload(pkt); |
|---|
| 508 |
dns_getdn(pkt, &cur, end, dn, sizeof(dn)); |
|---|
| 509 |
dns_initparse(&p, NULL, pkt, cur, end); |
|---|
| 510 |
p.dnsp_qcls = p.dnsp_qtyp = 0; |
|---|
| 511 |
nrr = 0; |
|---|
| 512 |
while((r = dns_nextrr(&p, &rr)) > 0) { |
|---|
| 513 |
if (!dns_dnequal(dn, rr.dnsrr_dn)) continue; |
|---|
| 514 |
if ((qcls == DNS_C_ANY || qcls == rr.dnsrr_cls) && |
|---|
| 515 |
(q->qtyp == DNS_T_ANY || q->qtyp == rr.dnsrr_typ)) |
|---|
| 516 |
++nrr; |
|---|
| 517 |
else if (rr.dnsrr_typ == DNS_T_CNAME && !nrr) { |
|---|
| 518 |
if (dns_getdn(pkt, &rr.dnsrr_dptr, end, |
|---|
| 519 |
p.dnsp_dnbuf, sizeof(p.dnsp_dnbuf)) <= 0 || |
|---|
| 520 |
rr.dnsrr_dptr != rr.dnsrr_dend) { |
|---|
| 521 |
r = DNS_E_PROTOCOL; |
|---|
| 522 |
break; |
|---|
| 523 |
} |
|---|
| 524 |
else { |
|---|
| 525 |
if (verbose == 1) { |
|---|
| 526 |
printf("%s.", dns_dntosp(dn)); |
|---|
| 527 |
printf(" CNAME %s.\n", dns_dntosp(p.dnsp_dnbuf)); |
|---|
| 528 |
} |
|---|
| 529 |
dns_dntodn(p.dnsp_dnbuf, dn, sizeof(dn)); |
|---|
| 530 |
} |
|---|
| 531 |
} |
|---|
| 532 |
} |
|---|
| 533 |
if (!r && !nrr) |
|---|
| 534 |
r = DNS_E_NODATA; |
|---|
| 535 |
if (r < 0) { |
|---|
| 536 |
dnserror(q, r); |
|---|
| 537 |
free(result); |
|---|
| 538 |
return; |
|---|
| 539 |
} |
|---|
| 540 |
if (verbose < 2) { /* else it is already printed by dbgfn */ |
|---|
| 541 |
dns_rewind(&p, NULL); |
|---|
| 542 |
p.dnsp_qtyp = q->qtyp == DNS_T_ANY ? 0 : q->qtyp; |
|---|
| 543 |
p.dnsp_qcls = qcls == DNS_C_ANY ? 0 : qcls; |
|---|
| 544 |
while(dns_nextrr(&p, &rr)) |
|---|
| 545 |
printrr(&p, &rr); |
|---|
| 546 |
} |
|---|
| 547 |
free(result); |
|---|
| 548 |
query_free(q); |
|---|
| 549 |
} |
|---|
| 550 |
|
|---|
| 551 |
int main(int argc, char **argv) { |
|---|
| 552 |
int i; |
|---|
| 553 |
int fd; |
|---|
| 554 |
fd_set fds; |
|---|
| 555 |
struct timeval tv; |
|---|
| 556 |
time_t now; |
|---|
| 557 |
char *ns[DNS_MAXSERV]; |
|---|
| 558 |
int nns = 0; |
|---|
| 559 |
struct query *q; |
|---|
| 560 |
enum dns_type qtyp = 0; |
|---|
| 561 |
struct dns_ctx *nctx = NULL; |
|---|
| 562 |
|
|---|
| 563 |
if (!(progname = strrchr(argv[0], '/'))) progname = argv[0]; |
|---|
| 564 |
else argv[0] = ++progname; |
|---|
| 565 |
|
|---|
| 566 |
if (argc <= 1) |
|---|
| 567 |
die(0, "try `%s -h' for help", progname); |
|---|
| 568 |
|
|---|
| 569 |
if (dns_init(NULL, 0) < 0 || !(nctx = dns_new(NULL))) |
|---|
| 570 |
die(errno, "unable to initialize dns library"); |
|---|
| 571 |
/* we keep two dns contexts: one may be needed to resolve |
|---|
| 572 |
* nameservers if given as names, using default options. |
|---|
| 573 |
*/ |
|---|
| 574 |
|
|---|
| 575 |
while((i = getopt(argc, argv, "vqt:c:an:o:h")) != EOF) switch(i) { |
|---|
| 576 |
case 'v': ++verbose; break; |
|---|
| 577 |
case 'q': --verbose; break; |
|---|
| 578 |
case 't': |
|---|
| 579 |
if (optarg[0] == '*' && !optarg[1]) |
|---|
| 580 |
i = DNS_T_ANY; |
|---|
| 581 |
else if ((i = dns_findtypename(optarg)) <= 0) |
|---|
| 582 |
die(0, "unrecognized query type `%s'", optarg); |
|---|
| 583 |
qtyp = i; |
|---|
| 584 |
break; |
|---|
| 585 |
case 'c': |
|---|
| 586 |
if (optarg[0] == '*' && !optarg[1]) |
|---|
| 587 |
i = DNS_C_ANY; |
|---|
| 588 |
else if ((i = dns_findclassname(optarg)) < 0) |
|---|
| 589 |
die(0, "unrecognized query class `%s'", optarg); |
|---|
| 590 |
qcls = i; |
|---|
| 591 |
break; |
|---|
| 592 |
case 'a': |
|---|
| 593 |
qtyp = DNS_T_ANY; |
|---|
| 594 |
++verbose; |
|---|
| 595 |
break; |
|---|
| 596 |
case 'n': |
|---|
| 597 |
if (nns >= DNS_MAXSERV) |
|---|
| 598 |
die(0, "too many nameservers, %d max", DNS_MAXSERV); |
|---|
| 599 |
ns[nns++] = optarg; |
|---|
| 600 |
break; |
|---|
| 601 |
case 'o': |
|---|
| 602 |
if (dns_set_opts(NULL, optarg) != 0) |
|---|
| 603 |
die(0, "invalid option string: `%s'", optarg); |
|---|
| 604 |
break; |
|---|
| 605 |
case 'h': |
|---|
| 606 |
printf( |
|---|
| 607 |
"%s: simple DNS query tool (using udns version %s)\n" |
|---|
| 608 |
"Usage: %s [options] domain-name...\n" |
|---|
| 609 |
"where options are:\n" |
|---|
| 610 |
" -h - print this help and exit\n" |
|---|
| 611 |
" -v - be more verbose\n" |
|---|
| 612 |
" -q - be less verbose\n" |
|---|
| 613 |
" -t type - set query type (A, AAA, PTR etc)\n" |
|---|
| 614 |
" -c class - set query class (IN (default), CH, HS, *)\n" |
|---|
| 615 |
" -a - equivalent to -t ANY -v\n" |
|---|
| 616 |
" -n ns - use given nameserver(s) instead of default\n" |
|---|
| 617 |
" (may be specified multiple times)\n" |
|---|
| 618 |
" -o option:value - set resovler option (the same as setting $RES_OPTIONS):\n" |
|---|
| 619 |
" timeout:sec - initial query timeout\n" |
|---|
| 620 |
" attempts:num - number of attempt to resovle a query\n" |
|---|
| 621 |
" ndots:num - if name has more than num dots, lookup it before search\n" |
|---|
| 622 |
" port:num - port number for queries instead of default 53\n" |
|---|
| 623 |
" udpbuf:num - size of UDP buffer (use EDNS0 if >512)\n" |
|---|
| 624 |
" (may be specified more than once)\n" |
|---|
| 625 |
, progname, dns_version(), progname); |
|---|
| 626 |
return 0; |
|---|
| 627 |
default: |
|---|
| 628 |
die(0, "try `%s -h' for help", progname); |
|---|
| 629 |
} |
|---|
| 630 |
|
|---|
| 631 |
argc -= optind; argv += optind; |
|---|
| 632 |
if (!argc) |
|---|
| 633 |
die(0, "no name(s) to query specified"); |
|---|
| 634 |
|
|---|
| 635 |
if (nns) { |
|---|
| 636 |
/* if nameservers given as names, resolve them. |
|---|
| 637 |
* We only allow IPv4 nameservers as names for now. |
|---|
| 638 |
* Ok, it is easy enouth to try both AAAA and A, |
|---|
| 639 |
* but the question is what to do by default. |
|---|
| 640 |
*/ |
|---|
| 641 |
struct sockaddr_in sin; |
|---|
| 642 |
int j, r = 0, opened = 0; |
|---|
| 643 |
memset(&sin, 0, sizeof(sin)); |
|---|
| 644 |
sin.sin_family = AF_INET; |
|---|
| 645 |
sin.sin_port = htons(dns_set_opt(NULL, DNS_OPT_PORT, -1)); |
|---|
| 646 |
dns_add_serv(NULL, NULL); |
|---|
| 647 |
for(i = 0; i < nns; ++i) { |
|---|
| 648 |
if (dns_pton(AF_INET, ns[i], &sin.sin_addr) <= 0) { |
|---|
| 649 |
struct dns_rr_a4 *rr; |
|---|
| 650 |
if (!opened) { |
|---|
| 651 |
if (dns_open(nctx) < 0) |
|---|
| 652 |
die(errno, "unable to initialize dns context"); |
|---|
| 653 |
opened = 1; |
|---|
| 654 |
} |
|---|
| 655 |
rr = dns_resolve_a4(nctx, ns[i], 0); |
|---|
| 656 |
if (!rr) |
|---|
| 657 |
die(0, "unable to resolve nameserver %s: %s", |
|---|
| 658 |
ns[i], dns_strerror(dns_status(nctx))); |
|---|
| 659 |
for(j = 0; j < rr->dnsa4_nrr; ++j) { |
|---|
| 660 |
sin.sin_addr = rr->dnsa4_addr[j]; |
|---|
| 661 |
if ((r = dns_add_serv_s(NULL, (struct sockaddr *)&sin)) < 0) |
|---|
| 662 |
break; |
|---|
| 663 |
} |
|---|
| 664 |
free(rr); |
|---|
| 665 |
} |
|---|
| 666 |
else |
|---|
| 667 |
r = dns_add_serv_s(NULL, (struct sockaddr *)&sin); |
|---|
| 668 |
if (r < 0) |
|---|
| 669 |
die(errno, "unable to add nameserver %s", |
|---|
| 670 |
dns_xntop(AF_INET, &sin.sin_addr)); |
|---|
| 671 |
} |
|---|
| 672 |
} |
|---|
| 673 |
dns_free(nctx); |
|---|
| 674 |
|
|---|
| 675 |
fd = dns_open(NULL); |
|---|
| 676 |
if (fd < 0) |
|---|
| 677 |
die(errno, "unable to initialize dns context"); |
|---|
| 678 |
|
|---|
| 679 |
if (verbose > 1) |
|---|
| 680 |
dns_set_dbgfn(NULL, dbgcb); |
|---|
| 681 |
|
|---|
| 682 |
for (i = 0; i < argc; ++i) { |
|---|
| 683 |
char *name = argv[i]; |
|---|
| 684 |
union { |
|---|
| 685 |
struct in_addr addr; |
|---|
| 686 |
struct in6_addr addr6; |
|---|
| 687 |
} a; |
|---|
| 688 |
unsigned char dn[DNS_MAXDN]; |
|---|
| 689 |
enum dns_type l_qtyp = 0; |
|---|
| 690 |
int abs; |
|---|
| 691 |
if (dns_pton(AF_INET, name, &a.addr) > 0) { |
|---|
| 692 |
dns_a4todn(&a.addr, 0, dn, sizeof(dn)); |
|---|
| 693 |
l_qtyp = DNS_T_PTR; |
|---|
| 694 |
abs = 1; |
|---|
| 695 |
} |
|---|
| 696 |
#ifdef HAVE_IPv6 |
|---|
| 697 |
else if (dns_pton(AF_INET6, name, &a.addr6) > 0) { |
|---|
| 698 |
dns_a6todn(&a.addr6, 0, dn, sizeof(dn)); |
|---|
| 699 |
l_qtyp = DNS_T_PTR; |
|---|
| 700 |
abs = 1; |
|---|
| 701 |
} |
|---|
| 702 |
#endif |
|---|
| 703 |
else if (!dns_ptodn(name, strlen(name), dn, sizeof(dn), &abs)) |
|---|
| 704 |
die(0, "invalid name `%s'\n", name); |
|---|
| 705 |
else |
|---|
| 706 |
l_qtyp = DNS_T_A; |
|---|
| 707 |
if (qtyp) l_qtyp = qtyp; |
|---|
| 708 |
q = query_new(name, dn, l_qtyp); |
|---|
| 709 |
if (abs) abs = DNS_NOSRCH; |
|---|
| 710 |
if (!dns_submit_dn(NULL, dn, qcls, l_qtyp, abs, 0, dnscb, q)) |
|---|
| 711 |
dnserror(q, dns_status(NULL)); |
|---|
| 712 |
} |
|---|
| 713 |
|
|---|
| 714 |
FD_ZERO(&fds); |
|---|
| 715 |
now = 0; |
|---|
| 716 |
while((i = dns_timeouts(NULL, -1, now)) > 0) { |
|---|
| 717 |
FD_SET(fd, &fds); |
|---|
| 718 |
tv.tv_sec = i; |
|---|
| 719 |
tv.tv_usec = 0; |
|---|
| 720 |
i = select(fd+1, &fds, 0, 0, &tv); |
|---|
| 721 |
now = time(NULL); |
|---|
| 722 |
if (i > 0) dns_ioevent(NULL, now); |
|---|
| 723 |
} |
|---|
| 724 |
|
|---|
| 725 |
return errors ? 1 : notfound ? 100 : 0; |
|---|
| 726 |
} |
|---|