Annotation of embedaddon/mtr/dns.c, revision 1.1
1.1 ! misho 1: /*
! 2: mtr -- a network diagnostic tool
! 3: Copyright (C) 1997,1998 Matt Kimball
! 4:
! 5: This program is free software; you can redistribute it and/or modify
! 6: it under the terms of the GNU General Public License version 2 as
! 7: published by the Free Software Foundation.
! 8:
! 9: This program is distributed in the hope that it will be useful,
! 10: but WITHOUT ANY WARRANTY; without even the implied warranty of
! 11: MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
! 12: GNU General Public License for more details.
! 13:
! 14: You should have received a copy of the GNU General Public License
! 15: along with this program; if not, write to the Free Software
! 16: Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
! 17: */
! 18:
! 19: /*
! 20: Non-blocking DNS portion --
! 21: Copyright (C) 1998 by Simon Kirby <sim@neato.org>
! 22: Released under GPL, as above.
! 23: */
! 24:
! 25: #include <config.h>
! 26: #include <sys/types.h>
! 27: #include <sys/time.h>
! 28: #include <sys/select.h>
! 29: #include <sys/stat.h>
! 30: #include <sys/errno.h>
! 31: #include <sys/socket.h>
! 32: #include <netinet/in.h>
! 33: #include <arpa/inet.h>
! 34:
! 35: #ifndef __APPLE__
! 36: #define BIND_8_COMPAT
! 37: #endif
! 38: #include <arpa/nameser.h>
! 39: #ifdef HAVE_ARPA_NAMESER_COMPAT_H
! 40: #include <arpa/nameser_compat.h>
! 41: #endif
! 42: #include <netdb.h>
! 43: #include <resolv.h>
! 44: #include <unistd.h>
! 45: #include <fcntl.h>
! 46: #include <ctype.h>
! 47: #include <string.h>
! 48: #include <stdio.h>
! 49: #include <stdlib.h>
! 50: #include <errno.h>
! 51: #include <time.h>
! 52:
! 53: #include "mtr.h"
! 54: #include "dns.h"
! 55: #include "net.h"
! 56:
! 57: #ifdef ENABLE_IPV6
! 58: #ifdef __GLIBC__
! 59: #define NSCOUNT6 myres._u._ext.nscount6
! 60: #define NSSOCKADDR6(i) (myres._u._ext.nsaddrs[i])
! 61: #else
! 62: #define NSCOUNT6 myres.nscount
! 63: #define NSSOCKADDR6(i) (&(myres._u._ext.ext->nsaddrs[i].sin6))
! 64: #endif
! 65: #endif
! 66:
! 67:
! 68: #ifdef NO_STRERROR
! 69: extern int sys_nerr;
! 70: extern char *sys_errlist[];
! 71: #define strerror(errno) (((errno) >= 0 && (errno) < sys_nerr) ? sys_errlist[errno] : "unlisted error")
! 72: #endif
! 73:
! 74: #if !HAVE_DECL_ERRNO
! 75: /* Hmm, it seems Irix requires this */
! 76: extern int errno;
! 77: #endif
! 78:
! 79: extern int af;
! 80:
! 81: /* Defines */
! 82:
! 83: #undef Debug
! 84:
! 85: #undef CorruptCheck
! 86: #undef WipeFrees
! 87: #undef WipeMallocs
! 88:
! 89: #define BashSize 8192 /* Size of hash tables */
! 90: #define BashModulo(x) ((x) & 8191) /* Modulo for hash table size: */
! 91: #define HostnameLength 255 /* From RFC */
! 92: #define ResRetryDelay1 3
! 93: #define ResRetryDelay2 4
! 94: #define ResRetryDelay3 5
! 95:
! 96: /* Macros */
! 97:
! 98: #define nonull(s) (s) ? s : nullstring
! 99:
! 100: /* Structures */
! 101:
! 102: struct resolve {
! 103: struct resolve *next;
! 104: struct resolve *previous;
! 105: struct resolve *nextid;
! 106: struct resolve *previousid;
! 107: struct resolve *nextip;
! 108: struct resolve *previousip;
! 109: struct resolve *nexthost;
! 110: struct resolve *previoushost;
! 111: float expiretime; /* Fucking HPUX has a problem with "double" here. */
! 112: char *hostname;
! 113: ip_t ip;
! 114: word id;
! 115: byte state;
! 116: };
! 117:
! 118: /* Non-blocking nameserver interface routines */
! 119:
! 120: #define MaxPacketsize (PACKETSZ)
! 121: #define DomainLength (MAXDNAME)
! 122:
! 123: #define OpcodeCount 3
! 124: char *opcodes[OpcodeCount+1] = {
! 125: "standard query",
! 126: "inverse query",
! 127: "server status request",
! 128: "unknown",
! 129: };
! 130:
! 131: #define ResponsecodeCount 6
! 132: char *responsecodes[ResponsecodeCount+1] = {
! 133: "no error",
! 134: "format error in query",
! 135: "server failure",
! 136: "queried domain name does not exist",
! 137: "requested query type not implemented",
! 138: "refused by name server",
! 139: "unknown error",
! 140: };
! 141:
! 142: #define ResourcetypeCount 17
! 143: char *resourcetypes[ResourcetypeCount+1] = {
! 144: "unknown type",
! 145: "A: host address",
! 146: "NS: authoritative name server",
! 147: "MD: mail destination (OBSOLETE)",
! 148: "MF: mail forwarder (OBSOLETE)",
! 149: "CNAME: name alias",
! 150: "SOA: authority record",
! 151: "MB: mailbox domain name (EXPERIMENTAL)",
! 152: "MG: mail group member (EXPERIMENTAL)",
! 153: "MR: mail rename domain name (EXPERIMENTAL)",
! 154: "NULL: NULL RR (EXPERIMENTAL)",
! 155: "WKS: well known service description",
! 156: "PTR: domain name pointer",
! 157: "HINFO: host information",
! 158: "MINFO: mailbox or mail list information",
! 159: "MX: mail exchange",
! 160: "TXT: text string",
! 161: "unknown type",
! 162: };
! 163:
! 164: #define ClasstypeCount 5
! 165: char *classtypes[ClasstypeCount+1] = {
! 166: "unknown class",
! 167: "IN: the Internet",
! 168: "CS: CSNET (OBSOLETE)",
! 169: "CH: CHAOS",
! 170: "HS: Hesoid [Dyer 87]",
! 171: "unknown class"
! 172: };
! 173:
! 174: char *rrtypes[] = {
! 175: "Unknown",
! 176: "Query",
! 177: "Answer",
! 178: "Authority reference",
! 179: "Resource reference",
! 180: };
! 181:
! 182:
! 183: /* Please don't use a trailing comma in enumerations: It doesn't
! 184: work on all compilers */
! 185: enum {
! 186: RR_UNKNOWN,
! 187: RR_QUERY,
! 188: RR_ANSWER,
! 189: RR_AUTHORITY,
! 190: RR_RESOURCE
! 191: };
! 192:
! 193: typedef struct {
! 194: word id; /* Packet id */
! 195: byte databyte_a;
! 196: /* rd:1 recursion desired
! 197: * tc:1 truncated message
! 198: * aa:1 authoritive answer
! 199: * opcode:4 purpose of message
! 200: * qr:1 response flag
! 201: */
! 202: byte databyte_b;
! 203: /* rcode:4 response code
! 204: * unassigned:2 unassigned bits
! 205: * pr:1 primary server required (non standard)
! 206: * ra:1 recursion available
! 207: */
! 208: word qdcount; /* Query record count */
! 209: word ancount; /* Answer record count */
! 210: word nscount; /* Authority reference record count */
! 211: word arcount; /* Resource reference record count */
! 212: } packetheader;
! 213:
! 214: #ifndef HFIXEDSZ
! 215: #define HFIXEDSZ (sizeof(packetheader))
! 216: #endif
! 217:
! 218: /*
! 219: * Byte order independent macros for packetheader
! 220: */
! 221: #define getheader_rd(x) (x->databyte_a & 1)
! 222: #define getheader_tc(x) ((x->databyte_a >> 1) & 1)
! 223: #define getheader_aa(x) ((x->databyte_a >> 2) & 1)
! 224: #define getheader_opcode(x) ((x->databyte_a >> 3) & 15)
! 225: #define getheader_qr(x) (x->databyte_a >> 7)
! 226: #define getheader_rcode(x) (x->databyte_b & 15)
! 227: #define getheader_pr(x) ((x->databyte_b >> 6) & 1)
! 228: #define getheader_ra(x) (x->databyte_b >> 7)
! 229:
! 230: #if 0
! 231:
! 232: /* The execution order inside an expression is undefined! That means that
! 233: this might work, but then again, it might not... */
! 234:
! 235: #define sucknetword(x) (((word)*(x) << 8) | (((x)+= 2)[-1]))
! 236: #define sucknetshort(x) (((short)*(x) << 8) | (((x)+= 2)[-1]))
! 237: #define sucknetdword(x) (((dword)*(x) << 24) | ((x)[1] << 16) | ((x)[2] << 8) | (((x)+= 4)[-1]))
! 238: #define sucknetlong(x) (((long)*(x) << 24) | ((x)[1] << 16) | ((x)[2] << 8) | (((x)+= 4)[-1]))
! 239: #else
! 240:
! 241: #define sucknetword(x) ((x)+=2,((word) (((x)[-2] << 8) | ((x)[-1] << 0))))
! 242: #define sucknetshort(x) ((x)+=2,((short) (((x)[-2] << 8) | ((x)[-1] << 0))))
! 243: #define sucknetdword(x) ((x)+=4,((dword) (((x)[-4] << 24) | ((x)[-3] << 16) | \
! 244: ((x)[-2] << 8) | ((x)[-1] << 0))))
! 245: #define sucknetlong(x) ((x)+=4,((long) (((x)[-4] << 24) | ((x)[-3] << 16) | \
! 246: ((x)[-2] << 8) | ((x)[-1] << 0))))
! 247: #endif
! 248:
! 249: enum {
! 250: STATE_FINISHED,
! 251: STATE_FAILED,
! 252: STATE_PTRREQ1,
! 253: STATE_PTRREQ2,
! 254: STATE_PTRREQ3
! 255: };
! 256:
! 257: #define Is_PTR(x) ((x->state == STATE_PTRREQ1) || (x->state == STATE_PTRREQ2) || (x->state == STATE_PTRREQ3))
! 258:
! 259: dword resrecvbuf[(MaxPacketsize + 7) >> 2]; /* MUST BE DWORD ALIGNED */
! 260:
! 261: struct resolve *idbash[BashSize];
! 262: struct resolve *ipbash[BashSize];
! 263: struct resolve *hostbash[BashSize];
! 264: struct resolve *expireresolves = NULL;
! 265: struct resolve *lastresolve = NULL;
! 266: struct logline *streamlog = NULL;
! 267: struct logline *lastlog = NULL;
! 268:
! 269: ip_t alignedip;
! 270: ip_t localhost;
! 271: #ifdef ENABLE_IPV6
! 272: ip_t localhost6;
! 273: #endif
! 274:
! 275: double sweeptime;
! 276:
! 277: #ifdef Debug
! 278: int debug = 1;
! 279: #else
! 280: int debug = 0;
! 281: #endif
! 282:
! 283: dword mem = 0;
! 284:
! 285: dword res_iplookupsuccess = 0;
! 286: dword res_reversesuccess = 0;
! 287: dword res_nxdomain = 0;
! 288: dword res_nserror = 0;
! 289: dword res_hostipmismatch = 0;
! 290: dword res_unknownid = 0;
! 291: dword res_resend = 0;
! 292: dword res_timeout = 0;
! 293:
! 294: dword resolvecount = 0;
! 295:
! 296: long idseed = 0xdeadbeef;
! 297: long aseed;
! 298:
! 299: #ifdef ENABLE_IPV6
! 300: struct sockaddr_storage from_sastruct;
! 301: struct sockaddr_in6 * from6 = (struct sockaddr_in6 *) &from_sastruct;
! 302: #else
! 303: struct sockaddr_in from_sastruct;
! 304: #endif
! 305:
! 306: struct sockaddr_in * from4 = (struct sockaddr_in *) &from_sastruct;
! 307: struct sockaddr * from = (struct sockaddr *) &from_sastruct;
! 308:
! 309: int resfd;
! 310: #ifdef ENABLE_IPV6
! 311: int resfd6;
! 312: #endif
! 313: socklen_t fromlen = sizeof from_sastruct;
! 314:
! 315: char tempstring[16384+1+1];
! 316: char sendstring[1024+1];
! 317: char namestring[1024+1];
! 318: char stackstring[1024+1];
! 319:
! 320: char nullstring[] = "";
! 321:
! 322: int use_dns = 1;
! 323:
! 324: #ifdef res_ninit
! 325: #define MY_RES_INIT() res_ninit(&myres);
! 326: #define RES_MKQUERY(a, b, c, d, e, f, g, h, i) \
! 327: res_nmkquery(&myres, a, b, c, d, e, f, g, h, i)
! 328: struct __res_state myres;
! 329: #else
! 330: #define MY_RES_INIT() res_init();
! 331: #define RES_MKQUERY(a, b, c, d, e, f, g, h, i) \
! 332: res_mkquery(a, b, c, d, e, f, g, h, i)
! 333: #define myres _res
! 334: #endif
! 335:
! 336: /* Code */
! 337: #ifdef CorruptCheck
! 338: #define TOT_SLACK 2
! 339: #define HEAD_SLACK 1
! 340: /* Need an entry for sparc systems here too.
! 341: Don't try this on Sparc for now. */
! 342: #else
! 343: #ifdef sparc
! 344: #define TOT_SLACK 2
! 345: #define HEAD_SLACK 2
! 346: #else
! 347: #define TOT_SLACK 1
! 348: #define HEAD_SLACK 1
! 349: #endif
! 350: #endif
! 351:
! 352:
! 353: void *statmalloc(size_t size)
! 354: {
! 355: void *p;
! 356: size_t mallocsize;
! 357:
! 358: mem+= size;
! 359: mallocsize = size + TOT_SLACK * sizeof(dword);
! 360:
! 361: p = malloc(mallocsize);
! 362: if (!p) {
! 363: fprintf(stderr,"malloc() of %u bytes failed: %s\n", (unsigned int)size, strerror(errno));
! 364: exit(-1);
! 365: }
! 366: *((dword *)p) = (dword)size;
! 367: #ifdef CorruptCheck
! 368: *(byte *)((char *)p + size + sizeof(dword) + sizeof(byte) * 0) = 0xde;
! 369: *(byte *)((char *)p + size + sizeof(dword) + sizeof(byte) * 1) = 0xad;
! 370: *(byte *)((char *)p + size + sizeof(dword) + sizeof(byte) * 2) = 0xbe;
! 371: *(byte *)((char *)p + size + sizeof(dword) + sizeof(byte) * 3) = 0xef;
! 372: #endif
! 373: p = (void *)((dword *)p + HEAD_SLACK);
! 374: #ifdef WipeMallocs
! 375: memset(p,0xf0,size);
! 376: #endif
! 377: return p;
! 378: }
! 379:
! 380:
! 381: void statfree(void *p)
! 382: {
! 383: if (p) {
! 384: if (*((dword *)p - HEAD_SLACK) == 0) {
! 385: fprintf(stderr,"ERROR: Attempt to free pointer twice.\n");
! 386: abort();
! 387: exit(-1);
! 388: } else {
! 389: if (*((dword *)p - HEAD_SLACK) > 8192) {
! 390: fprintf (stderr,"ERROR: Corrupted free() buffer. (header)\n");
! 391: abort();
! 392: exit(-1);
! 393: }
! 394: #ifdef CorruptCheck
! 395: if ((*(byte *)((char *)p + (*((dword *)p - 1)) + sizeof(byte) * 0) != 0xde) ||
! 396: (*(byte *)((char *)p + (*((dword *)p - 1)) + sizeof(byte) * 1) != 0xad) ||
! 397: (*(byte *)((char *)p + (*((dword *)p - 1)) + sizeof(byte) * 2) != 0xbe) ||
! 398: (*(byte *)((char *)p + (*((dword *)p - 1)) + sizeof(byte) * 3) != 0xef)) {
! 399: fprintf(stderr,"ERROR: Corrupted free() buffer. (footer)\n");
! 400: abort();
! 401: exit(-1);
! 402: }
! 403: #endif
! 404: mem-= *((dword *)p - HEAD_SLACK);
! 405: #ifdef WipeFrees
! 406: memset(p,0xfe,*((dword *)p - HEAD_SLACK));
! 407: *((dword *)p - 1) = 0;
! 408: #endif
! 409: free((dword *)p - HEAD_SLACK);
! 410: }
! 411: }
! 412: }
! 413:
! 414:
! 415: char *strtdiff(char *d,long signeddiff)
! 416: {
! 417: dword diff;
! 418: dword seconds,minutes,hours;
! 419: long days;
! 420:
! 421: if ((diff = labs(signeddiff))) {
! 422: seconds = diff % 60; diff/= 60;
! 423: minutes = diff % 60; diff/= 60;
! 424: hours = diff % 24;
! 425: days = signeddiff / (60 * 60 * 24);
! 426: if (days)
! 427: sprintf(d,"%lid",days);
! 428: else
! 429: *d = '\0';
! 430: if (hours)
! 431: sprintf(d + strlen(d),"%luh",hours);
! 432: if (minutes)
! 433: sprintf(d + strlen(d),"%lum",minutes);
! 434: if (seconds)
! 435: sprintf(d + strlen(d),"%lus",seconds);
! 436: } else
! 437: sprintf(d,"0s");
! 438: return d;
! 439: }
! 440:
! 441:
! 442: int issetfd(fd_set *set,int fd)
! 443: {
! 444: return (int)((FD_ISSET(fd,set)) && 1);
! 445: }
! 446:
! 447:
! 448: void setfd(fd_set *set,int fd)
! 449: {
! 450: FD_SET(fd,set);
! 451: }
! 452:
! 453:
! 454: void clearfd(fd_set *set,int fd)
! 455: {
! 456: FD_CLR(fd,set);
! 457: }
! 458:
! 459:
! 460: void clearset(fd_set *set)
! 461: {
! 462: FD_ZERO(set);
! 463: }
! 464:
! 465:
! 466: char *strlongip(ip_t * ip)
! 467: {
! 468: #ifdef ENABLE_IPV6
! 469: static char addrstr[INET6_ADDRSTRLEN];
! 470:
! 471: return (char *) inet_ntop( af, ip, addrstr, sizeof addrstr );
! 472: #else
! 473: return inet_ntoa( *ip );
! 474: #endif
! 475: }
! 476:
! 477:
! 478: int longipstr( char *s, ip_t *dst, int af )
! 479: {
! 480: #ifdef ENABLE_IPV6
! 481: return inet_pton( af, s, dst );
! 482: #else
! 483: return inet_aton( s, dst );
! 484: #endif
! 485: }
! 486:
! 487:
! 488: struct hostent * dns_forward(const char *name)
! 489: {
! 490: struct hostent *host;
! 491:
! 492: if ((host = gethostbyname(name)))
! 493: return host;
! 494: else
! 495: return NULL;
! 496: }
! 497:
! 498:
! 499: int dns_waitfd(void)
! 500: {
! 501: return resfd;
! 502: }
! 503: #ifdef ENABLE_IPV6
! 504: int dns_waitfd6(void)
! 505: {
! 506: return resfd6;
! 507: }
! 508: #endif
! 509:
! 510:
! 511: void dns_open(void)
! 512: {
! 513: int option,i;
! 514:
! 515: if (!dns) return;
! 516: MY_RES_INIT();
! 517: if (!myres.nscount) {
! 518: fprintf(stderr,"No nameservers defined.\n");
! 519: exit(-1);
! 520: }
! 521: myres.options|= RES_RECURSE | RES_DEFNAMES | RES_DNSRCH;
! 522: resfd = socket(AF_INET, SOCK_DGRAM, 0);
! 523: if (resfd == -1) {
! 524: fprintf(stderr,
! 525: "Unable to allocate IPv4 socket for nameserver communication: %s\n",
! 526: strerror(errno));
! 527: exit(-1);
! 528: }
! 529: #ifdef ENABLE_IPV6
! 530: resfd6 = socket(AF_INET6, SOCK_DGRAM, 0);
! 531: if (resfd6 == -1) {
! 532: fprintf(stderr,
! 533: "Unable to allocate IPv6 socket for nameserver communication: %s\n",
! 534: strerror(errno));
! 535: exit(-1);
! 536: }
! 537: #endif
! 538: option = 1;
! 539: if (setsockopt(resfd,SOL_SOCKET,SO_BROADCAST,(char *)&option,sizeof(option))) {
! 540: fprintf(stderr,
! 541: "Unable to setsockopt() on IPv4 nameserver communication socket: %s\n",
! 542: strerror(errno));
! 543: exit(-1);
! 544: }
! 545: #ifdef ENABLE_IPV6
! 546: if (setsockopt(resfd6,SOL_SOCKET,SO_BROADCAST,(char *)&option,sizeof(option))) {
! 547: fprintf(stderr,
! 548: "Unable to setsockopt() on IPv6 nameserver communication socket: %s\n",
! 549: strerror(errno));
! 550: exit(-1);
! 551: }
! 552: #endif
! 553: longipstr( "127.0.0.1", &localhost, AF_INET );
! 554: #ifdef ENABLE_IPV6
! 555: longipstr( "::1", &localhost6, AF_INET6 );
! 556: #endif
! 557: aseed = time(NULL) ^ (time(NULL) << 3) ^ (dword)getpid();
! 558: for (i = 0;i < BashSize;i++) {
! 559: idbash[i] = NULL;
! 560: hostbash[i] = NULL;
! 561: }
! 562: }
! 563:
! 564:
! 565: struct resolve *allocresolve(void)
! 566: {
! 567: struct resolve *rp;
! 568:
! 569: rp = (struct resolve *)statmalloc(sizeof(struct resolve));
! 570: if (!rp) {
! 571: fprintf(stderr,"statmalloc() failed: %s\n",strerror(errno));
! 572: exit(-1);
! 573: }
! 574: memset(rp,0, sizeof(struct resolve));
! 575: return rp;
! 576: }
! 577:
! 578:
! 579: dword getidbash(word id)
! 580: {
! 581: return (dword)BashModulo(id);
! 582: }
! 583:
! 584:
! 585: dword getipbash(ip_t * ip)
! 586: {
! 587: char *p = (char *) ip;
! 588: int i, len = 0;
! 589: dword bashvalue = 0;
! 590:
! 591: switch ( af ) {
! 592: case AF_INET:
! 593: len = sizeof (struct in_addr);
! 594: break;
! 595: #ifdef ENABLE_IPV6
! 596: case AF_INET6:
! 597: len = sizeof (struct in6_addr);
! 598: break;
! 599: #endif
! 600: }
! 601: for (i = 0; i < len; i++, p++) {
! 602: bashvalue^= *p;
! 603: bashvalue+= (*p >> 1) + (bashvalue >> 1);
! 604: }
! 605: return BashModulo(bashvalue);
! 606: }
! 607:
! 608:
! 609: dword gethostbash(char *host)
! 610: {
! 611: dword bashvalue = 0;
! 612:
! 613: for (;*host;host++) {
! 614: bashvalue^= *host;
! 615: bashvalue+= (*host >> 1) + (bashvalue >> 1);
! 616: }
! 617: return BashModulo(bashvalue);
! 618: }
! 619:
! 620:
! 621: void linkresolveid(struct resolve *addrp)
! 622: {
! 623: struct resolve *rp;
! 624: dword bashnum;
! 625:
! 626: bashnum = getidbash(addrp->id);
! 627: rp = idbash[bashnum];
! 628: if (rp) {
! 629: while ((rp->nextid) && (addrp->id > rp->nextid->id))
! 630: rp = rp->nextid;
! 631: while ((rp->previousid) && (addrp->id < rp->previousid->id))
! 632: rp = rp->previousid;
! 633: if (rp->id < addrp->id) {
! 634: addrp->previousid = rp;
! 635: addrp->nextid = rp->nextid;
! 636: if (rp->nextid)
! 637: rp->nextid->previousid = addrp;
! 638: rp->nextid = addrp;
! 639: } else {
! 640: addrp->previousid = rp->previousid;
! 641: addrp->nextid = rp;
! 642: if (rp->previousid)
! 643: rp->previousid->nextid = addrp;
! 644: rp->previousid = addrp;
! 645: }
! 646: } else
! 647: addrp->nextid = addrp->previousid = NULL;
! 648: idbash[bashnum] = addrp;
! 649: }
! 650:
! 651:
! 652: void unlinkresolveid(struct resolve *rp)
! 653: {
! 654: dword bashnum;
! 655:
! 656: bashnum = getidbash(rp->id);
! 657: if (idbash[bashnum] == rp)
! 658: idbash[bashnum] = (rp->previousid)? rp->previousid : rp->nextid;
! 659: if (rp->nextid)
! 660: rp->nextid->previousid = rp->previousid;
! 661: if (rp->previousid)
! 662: rp->previousid->nextid = rp->nextid;
! 663: }
! 664:
! 665:
! 666: void linkresolvehost(struct resolve *addrp)
! 667: {
! 668: struct resolve *rp;
! 669: dword bashnum;
! 670:
! 671: bashnum = gethostbash(addrp->hostname);
! 672: rp = hostbash[bashnum];
! 673: if (rp) {
! 674: while ((rp->nexthost) && (strcasecmp(addrp->hostname,rp->nexthost->hostname) < 0))
! 675: rp = rp->nexthost;
! 676: while ((rp->previoushost) && (strcasecmp(addrp->hostname,rp->previoushost->hostname) > 0))
! 677: rp = rp->previoushost;
! 678: if (strcasecmp(addrp->hostname,rp->hostname) < 0) {
! 679: addrp->previoushost = rp;
! 680: addrp->nexthost = rp->nexthost;
! 681: if (rp->nexthost)
! 682: rp->nexthost->previoushost = addrp;
! 683: rp->nexthost = addrp;
! 684: } else {
! 685: addrp->previoushost = rp->previoushost;
! 686: addrp->nexthost = rp;
! 687: if (rp->previoushost)
! 688: rp->previoushost->nexthost = addrp;
! 689: rp->previoushost = addrp;
! 690: }
! 691: } else
! 692: addrp->nexthost = addrp->previoushost = NULL;
! 693: hostbash[bashnum] = addrp;
! 694: }
! 695:
! 696:
! 697: void unlinkresolvehost(struct resolve *rp)
! 698: {
! 699: dword bashnum;
! 700:
! 701: bashnum = gethostbash(rp->hostname);
! 702: if (hostbash[bashnum] == rp)
! 703: hostbash[bashnum] = (rp->previoushost)? rp->previoushost : rp->nexthost;
! 704: if (rp->nexthost)
! 705: rp->nexthost->previoushost = rp->previoushost;
! 706: if (rp->previoushost)
! 707: rp->previoushost->nexthost = rp->nexthost;
! 708: statfree(rp->hostname);
! 709: }
! 710:
! 711:
! 712: void linkresolveip(struct resolve *addrp)
! 713: {
! 714: struct resolve *rp;
! 715: dword bashnum;
! 716:
! 717: bashnum = getipbash( &(addrp->ip) );
! 718: rp = ipbash[bashnum];
! 719: if (rp) {
! 720: while ((rp->nextip) &&
! 721: ( addrcmp( (void *) &(addrp->ip),
! 722: (void *) &(rp->nextip->ip), af ) > 0 ))
! 723: rp = rp->nextip;
! 724: while ((rp->previousip) &&
! 725: ( addrcmp( (void *) &(addrp->ip),
! 726: (void *) &(rp->previousip->ip), af ) < 0 ))
! 727: rp = rp->previousip;
! 728: if ( addrcmp( (void *) &(rp->ip), (void *) &(addrp->ip), af ) < 0 ) {
! 729: addrp->previousip = rp;
! 730: addrp->nextip = rp->nextip;
! 731: if (rp->nextip)
! 732: rp->nextip->previousip = addrp;
! 733: rp->nextip = addrp;
! 734: } else {
! 735: addrp->previousip = rp->previousip;
! 736: addrp->nextip = rp;
! 737: if (rp->previousip)
! 738: rp->previousip->nextip = addrp;
! 739: rp->previousip = addrp;
! 740: }
! 741: } else
! 742: addrp->nextip = addrp->previousip = NULL;
! 743: ipbash[bashnum] = addrp;
! 744: }
! 745:
! 746:
! 747: void unlinkresolveip(struct resolve *rp)
! 748: {
! 749: dword bashnum;
! 750:
! 751: bashnum = getipbash( &(rp->ip) );
! 752: if (ipbash[bashnum] == rp)
! 753: ipbash[bashnum] = (rp->previousip)? rp->previousip : rp->nextip;
! 754: if (rp->nextip)
! 755: rp->nextip->previousip = rp->previousip;
! 756: if (rp->previousip)
! 757: rp->previousip->nextip = rp->nextip;
! 758: }
! 759:
! 760:
! 761: void linkresolve(struct resolve *rp)
! 762: {
! 763: struct resolve *irp;
! 764:
! 765: if (expireresolves) {
! 766: irp = expireresolves;
! 767: while ((irp->next) && (rp->expiretime >= irp->expiretime)) irp = irp->next;
! 768: if (rp->expiretime >= irp->expiretime) {
! 769: rp->next = NULL;
! 770: rp->previous = irp;
! 771: irp->next = rp;
! 772: lastresolve = rp;
! 773: } else {
! 774: rp->previous = irp->previous;
! 775: rp->next = irp;
! 776: if (irp->previous)
! 777: irp->previous->next = rp;
! 778: else
! 779: expireresolves = rp;
! 780: irp->previous = rp;
! 781: }
! 782: } else {
! 783: rp->next = NULL;
! 784: rp->previous = NULL;
! 785: expireresolves = lastresolve = rp;
! 786: }
! 787: resolvecount++;
! 788: }
! 789:
! 790:
! 791: void lastlinkresolve(struct resolve *rp)
! 792: {
! 793: struct resolve *irp;
! 794:
! 795: if (lastresolve) {
! 796: irp = lastresolve;
! 797: while ((irp->previous) && (rp->expiretime < irp->expiretime)) irp = irp->previous;
! 798: while ((irp->next) && (rp->expiretime >= irp->expiretime)) irp = irp->next;
! 799: if (rp->expiretime >= irp->expiretime) {
! 800: rp->next = NULL;
! 801: rp->previous = irp;
! 802: irp->next = rp;
! 803: lastresolve = rp;
! 804: } else {
! 805: rp->previous = irp->previous;
! 806: rp->next = irp;
! 807: if (irp->previous)
! 808: irp->previous->next = rp;
! 809: else
! 810: expireresolves = rp;
! 811: irp->previous = rp;
! 812: }
! 813: } else {
! 814: rp->next = NULL;
! 815: rp->previous = NULL;
! 816: expireresolves = lastresolve = rp;
! 817: }
! 818: resolvecount++;
! 819: }
! 820:
! 821:
! 822: void untieresolve(struct resolve *rp)
! 823: {
! 824: if (rp->previous)
! 825: rp->previous->next = rp->next;
! 826: else
! 827: expireresolves = rp->next;
! 828: if (rp->next)
! 829: rp->next->previous = rp->previous;
! 830: else
! 831: lastresolve = rp->previous;
! 832: resolvecount--;
! 833: }
! 834:
! 835:
! 836: void unlinkresolve(struct resolve *rp)
! 837: {
! 838: untieresolve(rp);
! 839: unlinkresolveid(rp);
! 840: unlinkresolveip(rp);
! 841: if (rp->hostname)
! 842: unlinkresolvehost(rp);
! 843: }
! 844:
! 845:
! 846: struct resolve *findid(word id)
! 847: {
! 848: struct resolve *rp;
! 849: int bashnum;
! 850:
! 851: bashnum = getidbash(id);
! 852: rp = idbash[bashnum];
! 853: if (rp) {
! 854: while ((rp->nextid) && (id >= rp->nextid->id))
! 855: rp = rp->nextid;
! 856: while ((rp->previousid) && (id <= rp->previousid->id))
! 857: rp = rp->previousid;
! 858: if (id == rp->id) {
! 859: idbash[bashnum] = rp;
! 860: return rp;
! 861: } else
! 862: return NULL;
! 863: }
! 864: return rp; /* NULL */
! 865: }
! 866:
! 867:
! 868: struct resolve *findhost(char *hostname)
! 869: {
! 870: struct resolve *rp;
! 871: int bashnum;
! 872:
! 873: bashnum = gethostbash(hostname);
! 874: rp = hostbash[bashnum];
! 875: if (rp) {
! 876: while ((rp->nexthost) && (strcasecmp(hostname,rp->nexthost->hostname) >= 0))
! 877: rp = rp->nexthost;
! 878: while ((rp->previoushost) && (strcasecmp(hostname,rp->nexthost->hostname) <= 0))
! 879: rp = rp->previoushost;
! 880: if (strcasecmp(hostname,rp->hostname))
! 881: return NULL;
! 882: else {
! 883: hostbash[bashnum] = rp;
! 884: return rp;
! 885: }
! 886: }
! 887: return rp; /* NULL */
! 888: }
! 889:
! 890:
! 891: struct resolve *findip(ip_t * ip)
! 892: {
! 893: struct resolve *rp;
! 894: dword bashnum;
! 895:
! 896: bashnum = getipbash(ip);
! 897: rp = ipbash[bashnum];
! 898: if (rp) {
! 899: while ((rp->nextip) &&
! 900: ( addrcmp( (void *) ip, (void *) &(rp->nextip->ip), af ) >= 0 ))
! 901: rp = rp->nextip;
! 902: while ((rp->previousip) &&
! 903: ( addrcmp( (void *) ip, (void *) &(rp->previousip->ip), af ) <= 0 ))
! 904: rp = rp->previousip;
! 905: if ( addrcmp( (void *) ip, (void *) &(rp->ip), af ) == 0 ) {
! 906: ipbash[bashnum] = rp;
! 907: return rp;
! 908: } else
! 909: return NULL;
! 910: }
! 911: return rp; /* NULL */
! 912: }
! 913:
! 914:
! 915: void restell(char *s)
! 916: {
! 917: fputs(s,stderr);
! 918: fputs("\r",stderr);
! 919: }
! 920:
! 921:
! 922: void dorequest(char *s,int type,word id)
! 923: {
! 924: packetheader *hp;
! 925: int r,i;
! 926: unsigned char buf[MaxPacketsize];
! 927:
! 928: r = RES_MKQUERY(QUERY,s,C_IN,type,NULL,0,NULL,(unsigned char*)buf,MaxPacketsize);
! 929: if (r == -1) {
! 930: restell("Resolver error: Query too large.");
! 931: return;
! 932: }
! 933: hp = (packetheader *)buf;
! 934: hp->id = id; /* htons() deliberately left out (redundant) */
! 935: #ifdef ENABLE_IPV6
! 936: for (i = 0;i < NSCOUNT6;i++) {
! 937: if (!NSSOCKADDR6(i))
! 938: continue;
! 939: if (NSSOCKADDR6(i)->sin6_family == AF_INET6)
! 940: (void)sendto(resfd6,buf,r,0,(struct sockaddr *) NSSOCKADDR6(i),
! 941: sizeof(struct sockaddr_in6));
! 942: }
! 943: #endif
! 944: for (i = 0;i < myres.nscount;i++)
! 945: if (myres.nsaddr_list[i].sin_family == AF_INET)
! 946: (void)sendto(resfd,buf,r,0,(struct sockaddr *)&myres.nsaddr_list[i],
! 947: sizeof(struct sockaddr));
! 948: }
! 949:
! 950: void resendrequest(struct resolve *rp,int type)
! 951: {
! 952: if (type == T_A) {
! 953: dorequest(rp->hostname,type,rp->id);
! 954: if (debug) {
! 955: snprintf(tempstring, sizeof(tempstring), "Resolver: Sent reverse authentication request for \"%s\".",
! 956: rp->hostname);
! 957: restell(tempstring);
! 958: }
! 959: } else if (type == T_PTR) {
! 960: switch ( af ) {
! 961: case AF_INET:
! 962: sprintf(tempstring,"%u.%u.%u.%u.in-addr.arpa",
! 963: ((byte *)&rp->ip)[3],
! 964: ((byte *)&rp->ip)[2],
! 965: ((byte *)&rp->ip)[1],
! 966: ((byte *)&rp->ip)[0]);
! 967: break;
! 968: #ifdef ENABLE_IPV6
! 969: case AF_INET6:
! 970: addr2ip6arpa( &(rp->ip), tempstring );
! 971: break;
! 972: #endif
! 973: }
! 974: dorequest(tempstring,type,rp->id);
! 975: if (debug) {
! 976: snprintf(tempstring, sizeof(tempstring), "Resolver: Sent domain lookup request for \"%s\".",
! 977: strlongip( &(rp->ip) ));
! 978: restell(tempstring);
! 979: }
! 980: }
! 981: }
! 982:
! 983: void sendrequest(struct resolve *rp,int type)
! 984: {
! 985: do {
! 986: idseed = (((idseed + idseed) | (long)time(NULL)) + idseed - 0x54bad4a) ^ aseed;
! 987: aseed^= idseed;
! 988: rp->id = (word)idseed;
! 989: } while (findid(rp->id));
! 990: linkresolveid(rp);
! 991: resendrequest(rp,type);
! 992: }
! 993:
! 994:
! 995: void failrp(struct resolve *rp)
! 996: {
! 997: if (rp->state == STATE_FINISHED)
! 998: return;
! 999: rp->state = STATE_FAILED;
! 1000: untieresolve(rp);
! 1001: if (debug)
! 1002: restell("Resolver: Lookup failed.\n");
! 1003: }
! 1004:
! 1005:
! 1006: void passrp(struct resolve *rp,long ttl)
! 1007: {
! 1008: rp->state = STATE_FINISHED;
! 1009: rp->expiretime = sweeptime + (double)ttl;
! 1010: untieresolve(rp);
! 1011: if (debug) {
! 1012: snprintf(tempstring, sizeof(tempstring), "Resolver: Lookup successful: %s\n",rp->hostname);
! 1013: restell(tempstring);
! 1014: }
! 1015: }
! 1016:
! 1017:
! 1018: void parserespacket(byte *s, int l)
! 1019: {
! 1020: struct resolve *rp;
! 1021: packetheader *hp;
! 1022: byte *eob;
! 1023: byte *c;
! 1024: long ttl;
! 1025: int r,usefulanswer;
! 1026: word rr,datatype,class,qdatatype,qclass;
! 1027: byte rdatalength;
! 1028:
! 1029: if (l < (int) sizeof(packetheader)) {
! 1030: restell("Resolver error: Packet smaller than standard header size.");
! 1031: return;
! 1032: }
! 1033: if (l == (int) sizeof(packetheader)) {
! 1034: restell("Resolver error: Packet has empty body.");
! 1035: return;
! 1036: }
! 1037: hp = (packetheader *)s;
! 1038: /* Convert data to host byte order */
! 1039: /* hp->id does not need to be redundantly byte-order flipped, it is only echoed by nameserver */
! 1040: rp = findid(hp->id);
! 1041: if (!rp) {
! 1042: res_unknownid++;
! 1043: return;
! 1044: }
! 1045: if ((rp->state == STATE_FINISHED) || (rp->state == STATE_FAILED))
! 1046: return;
! 1047: hp->qdcount = ntohs(hp->qdcount);
! 1048: hp->ancount = ntohs(hp->ancount);
! 1049: hp->nscount = ntohs(hp->nscount);
! 1050: hp->arcount = ntohs(hp->arcount);
! 1051: if (getheader_tc(hp)) { /* Packet truncated */
! 1052: restell("Resolver error: Nameserver packet truncated.");
! 1053: return;
! 1054: }
! 1055: if (!getheader_qr(hp)) { /* Not a reply */
! 1056: restell("Resolver error: Query packet received on nameserver communication socket.");
! 1057: return;
! 1058: }
! 1059: if (getheader_opcode(hp)) { /* Not opcode 0 (standard query) */
! 1060: restell("Resolver error: Invalid opcode in response packet.");
! 1061: return;
! 1062: }
! 1063: eob = s + l;
! 1064: c = s + HFIXEDSZ;
! 1065: switch (getheader_rcode(hp)) {
! 1066: case NOERROR:
! 1067: if (hp->ancount) {
! 1068: if (debug) {
! 1069: snprintf(tempstring, sizeof(tempstring), "Resolver: Received nameserver reply. (qd:%u an:%u ns:%u ar:%u)",
! 1070: hp->qdcount,hp->ancount,hp->nscount,hp->arcount);
! 1071: restell(tempstring);
! 1072: }
! 1073: if (hp->qdcount != 1) {
! 1074: restell("Resolver error: Reply does not contain one query.");
! 1075: return;
! 1076: }
! 1077: if (c > eob) {
! 1078: restell("Resolver error: Reply too short.");
! 1079: return;
! 1080: }
! 1081: switch (rp->state) { /* Construct expected query reply */
! 1082: case STATE_PTRREQ1:
! 1083: case STATE_PTRREQ2:
! 1084: case STATE_PTRREQ3:
! 1085: switch ( af ) {
! 1086: case AF_INET:
! 1087: sprintf(stackstring,"%u.%u.%u.%u.in-addr.arpa",
! 1088: ((byte *)&rp->ip)[3],
! 1089: ((byte *)&rp->ip)[2],
! 1090: ((byte *)&rp->ip)[1],
! 1091: ((byte *)&rp->ip)[0]);
! 1092: break;
! 1093: #ifdef ENABLE_IPV6
! 1094: case AF_INET6:
! 1095: addr2ip6arpa( &(rp->ip), stackstring );
! 1096: break;
! 1097: #endif
! 1098: }
! 1099: }
! 1100: *namestring = '\0';
! 1101: r = dn_expand(s,s + l,c,namestring,MAXDNAME);
! 1102: if (r == -1) {
! 1103: restell("Resolver error: dn_expand() failed while expanding query domain.");
! 1104: return;
! 1105: }
! 1106: namestring[strlen(stackstring)] = '\0';
! 1107: if (strcasecmp(stackstring,namestring)) {
! 1108: if (debug) {
! 1109: snprintf(tempstring, sizeof(tempstring), "Resolver: Unknown query packet dropped. (\"%s\" does not match \"%s\")",
! 1110: stackstring,namestring);
! 1111: restell(tempstring);
! 1112: }
! 1113: return;
! 1114: }
! 1115: if (debug) {
! 1116: snprintf(tempstring, sizeof(tempstring), "Resolver: Queried domain name: \"%s\"",namestring);
! 1117: restell(tempstring);
! 1118: }
! 1119: c+= r;
! 1120: if (c + 4 > eob) {
! 1121: restell("Resolver error: Query resource record truncated.");
! 1122: return;
! 1123: }
! 1124: qdatatype = sucknetword(c);
! 1125: qclass = sucknetword(c);
! 1126: if (qclass != C_IN) {
! 1127: snprintf(tempstring, sizeof(tempstring), "Resolver error: Received unsupported query class: %u (%s)",
! 1128: qclass,qclass < ClasstypeCount ? classtypes[qclass] :
! 1129: classtypes[ClasstypeCount]);
! 1130: restell(tempstring);
! 1131: }
! 1132: switch (qdatatype) {
! 1133: case T_PTR:
! 1134: if (!Is_PTR(rp))
! 1135: if (debug) {
! 1136: restell("Resolver warning: Ignoring response with unexpected query type \"PTR\".");
! 1137: return;
! 1138: }
! 1139: break;
! 1140: default:
! 1141: snprintf(tempstring, sizeof(tempstring), "Resolver error: Received unimplemented query type: %u (%s)",
! 1142: qdatatype,qdatatype < ResourcetypeCount ?
! 1143: resourcetypes[qdatatype] : resourcetypes[ResourcetypeCount]);
! 1144: restell(tempstring);
! 1145: }
! 1146: for (rr = hp->ancount + hp->nscount + hp->arcount;rr;rr--) {
! 1147: if (c > eob) {
! 1148: restell("Resolver error: Packet does not contain all specified resouce records.");
! 1149: return;
! 1150: }
! 1151: *namestring = '\0';
! 1152: r = dn_expand(s,s + l,c,namestring,MAXDNAME);
! 1153: if (r == -1) {
! 1154: restell("Resolver error: dn_expand() failed while expanding answer domain.");
! 1155: return;
! 1156: }
! 1157: namestring[strlen(stackstring)] = '\0';
! 1158: if (strcasecmp(stackstring,namestring))
! 1159: usefulanswer = 0;
! 1160: else
! 1161: usefulanswer = 1;
! 1162: if (debug) {
! 1163: snprintf(tempstring, sizeof(tempstring), "Resolver: answered domain query: \"%s\"",namestring);
! 1164: restell(tempstring);
! 1165: }
! 1166: c+= r;
! 1167: if (c + 10 > eob) {
! 1168: restell("Resolver error: Resource record truncated.");
! 1169: return;
! 1170: }
! 1171: datatype = sucknetword(c);
! 1172: class = sucknetword(c);
! 1173: ttl = sucknetlong(c);
! 1174: rdatalength = sucknetword(c);
! 1175: if (class != qclass) {
! 1176: snprintf(tempstring, sizeof(tempstring), "query class: %u (%s)",qclass,qclass < ClasstypeCount ?
! 1177: classtypes[qclass] : classtypes[ClasstypeCount]);
! 1178: restell(tempstring);
! 1179: snprintf(tempstring, sizeof(tempstring), "rr class: %u (%s)",class,class < ClasstypeCount ?
! 1180: classtypes[class] : classtypes[ClasstypeCount]);
! 1181: restell(tempstring);
! 1182: restell("Resolver error: Answered class does not match queried class.");
! 1183: return;
! 1184: }
! 1185: if (!rdatalength) {
! 1186: restell("Resolver error: Zero size rdata.");
! 1187: return;
! 1188: }
! 1189: if (c + rdatalength > eob) {
! 1190: restell("Resolver error: Specified rdata length exceeds packet size.");
! 1191: return;
! 1192: }
! 1193: if (datatype == qdatatype || datatype == T_CNAME) {
! 1194: if (debug) {
! 1195: snprintf(tempstring, sizeof(tempstring), "Resolver: TTL: %s",strtdiff(sendstring,ttl));
! 1196: restell(tempstring);
! 1197: }
! 1198: if (usefulanswer)
! 1199: switch (datatype) {
! 1200: case T_A:
! 1201: if (rdatalength != 4) {
! 1202: snprintf(tempstring, sizeof(tempstring), "Resolver error: Unsupported rdata format for \"A\" type. (%u bytes)",
! 1203: rdatalength);
! 1204: restell(tempstring);
! 1205: return;
! 1206: }
! 1207: if ( addrcmp( (void *) &(rp->ip), (void *) c, af ) == 0 ) {
! 1208: snprintf(tempstring, sizeof(tempstring), "Resolver: Reverse authentication failed: %s != ",
! 1209: strlongip( &(rp->ip) ));
! 1210: addrcpy( (void *) &alignedip, (void *) c, af );
! 1211: strcat(tempstring,strlongip( &alignedip ));
! 1212: restell(tempstring);
! 1213: res_hostipmismatch++;
! 1214: failrp(rp);
! 1215: } else {
! 1216: snprintf(tempstring, sizeof(tempstring), "Resolver: Reverse authentication complete: %s == \"%s\".",
! 1217: strlongip( &(rp->ip) ),nonull(rp->hostname));
! 1218: restell(tempstring);
! 1219: res_reversesuccess++;
! 1220: passrp(rp,ttl);
! 1221: return;
! 1222: }
! 1223: break;
! 1224: case T_PTR:
! 1225: case T_CNAME:
! 1226: *namestring = '\0';
! 1227: r = dn_expand(s,s + l,c,namestring,MAXDNAME);
! 1228: if (r == -1) {
! 1229: restell("Resolver error: dn_expand() failed while expanding domain in rdata.");
! 1230: return;
! 1231: }
! 1232: if (debug) {
! 1233: snprintf(tempstring, sizeof(tempstring), "Resolver: Answered domain: \"%s\"",namestring);
! 1234: restell(tempstring);
! 1235: }
! 1236: if (r > HostnameLength) {
! 1237: restell("Resolver error: Domain name too long.");
! 1238: failrp(rp);
! 1239: return;
! 1240: }
! 1241: if (datatype == T_CNAME) {
! 1242: strcpy(stackstring,namestring);
! 1243: break;
! 1244: }
! 1245: if (!rp->hostname) {
! 1246: rp->hostname = (char *)statmalloc(strlen(namestring) + 1);
! 1247: if (!rp->hostname) {
! 1248: fprintf(stderr,"statmalloc() error: %s\n",strerror(errno));
! 1249: exit(-1);
! 1250: }
! 1251: strcpy(rp->hostname,namestring);
! 1252: linkresolvehost(rp);
! 1253: passrp(rp,ttl);
! 1254: res_iplookupsuccess++;
! 1255: }
! 1256: break;
! 1257: default:
! 1258: snprintf(tempstring, sizeof(tempstring), "Resolver error: Received unimplemented data type: %u (%s)",
! 1259: datatype,datatype < ResourcetypeCount ?
! 1260: resourcetypes[datatype] : resourcetypes[ResourcetypeCount]);
! 1261: restell(tempstring);
! 1262: }
! 1263: } else {
! 1264: if (debug) {
! 1265: snprintf(tempstring, sizeof(tempstring), "Resolver: Ignoring resource type %u. (%s)",
! 1266: datatype,datatype < ResourcetypeCount ?
! 1267: resourcetypes[datatype] : resourcetypes[ResourcetypeCount]);
! 1268: restell(tempstring);
! 1269: }
! 1270: }
! 1271: c+= rdatalength;
! 1272: }
! 1273: } else
! 1274: restell("Resolver error: No error returned but no answers given.");
! 1275: break;
! 1276: case NXDOMAIN:
! 1277: if (debug)
! 1278: restell("Resolver: Host not found.");
! 1279: res_nxdomain++;
! 1280: failrp(rp);
! 1281: break;
! 1282: default:
! 1283: snprintf(tempstring, sizeof(tempstring), "Resolver: Received error response %u. (%s)",
! 1284: getheader_rcode(hp),getheader_rcode(hp) < ResponsecodeCount ?
! 1285: responsecodes[getheader_rcode(hp)] : responsecodes[ResponsecodeCount]);
! 1286: restell(tempstring);
! 1287: res_nserror++;
! 1288: }
! 1289: }
! 1290:
! 1291:
! 1292: void dns_ack(void)
! 1293: {
! 1294: int r,i;
! 1295:
! 1296: r = recvfrom(resfd,(byte *)resrecvbuf,MaxPacketsize,0,
! 1297: from, &fromlen);
! 1298: if (r > 0) {
! 1299: /* Check to see if this server is actually one we sent to */
! 1300: if ( addrcmp( (void *) &(from4->sin_addr), (void *) &localhost,
! 1301: (int) AF_INET ) == 0 ) {
! 1302: for (i = 0;i < myres.nscount;i++)
! 1303: if ( addrcmp( (void *) &(myres.nsaddr_list[i].sin_addr),
! 1304: (void *) &(from4->sin_addr), (int) AF_INET ) == 0 ||
! 1305: addrcmp( (void *) &(myres.nsaddr_list[i].sin_addr),
! 1306: (void *) &unspec_addr, (int) AF_INET ) == 0 ) /* 0.0.0.0 replies as 127.0.0.1 */
! 1307: break;
! 1308: } else
! 1309: for (i = 0;i < myres.nscount;i++)
! 1310: if ( addrcmp( (void *) &(myres.nsaddr_list[i].sin_addr),
! 1311: (void *) &(from4->sin_addr), AF_INET ) == 0 )
! 1312: break;
! 1313: if (i == myres.nscount) {
! 1314: snprintf(tempstring, sizeof(tempstring), "Resolver error: Received reply from unknown source: %s",
! 1315: inet_ntoa(from4->sin_addr ));
! 1316: restell(tempstring);
! 1317: } else
! 1318: parserespacket((byte *)resrecvbuf,r);
! 1319: } else {
! 1320: snprintf(tempstring, sizeof(tempstring), "Resolver: Socket error: %s",strerror(errno));
! 1321: restell(tempstring);
! 1322: }
! 1323: }
! 1324: #ifdef ENABLE_IPV6
! 1325: void dns_ack6(void)
! 1326: {
! 1327: int r,i;
! 1328: static char addrstr[INET6_ADDRSTRLEN];
! 1329:
! 1330: r = recvfrom(resfd6,(byte *)resrecvbuf,MaxPacketsize,0,
! 1331: from, &fromlen);
! 1332: if (r > 0) {
! 1333: /* Check to see if this server is actually one we sent to */
! 1334: if ( addrcmp( (void *) &(from6->sin6_addr), (void *) &localhost6,
! 1335: (int) AF_INET6 ) == 0 ) {
! 1336: for (i = 0;i < NSCOUNT6;i++) {
! 1337: if (!NSSOCKADDR6(i))
! 1338: continue;
! 1339:
! 1340: if ( addrcmp( (void *) &(NSSOCKADDR6(i)->sin6_addr),
! 1341: (void *) &(from6->sin6_addr), (int) AF_INET6 ) == 0 ||
! 1342: addrcmp( (void *) &(NSSOCKADDR6(i)->sin6_addr),
! 1343: (void *) &unspec_addr, (int) AF_INET6 ) == 0 ) /* 0.0.0.0 replies as 127.0.0.1 */
! 1344: break;
! 1345: }
! 1346: } else
! 1347: for (i = 0;i < NSCOUNT6;i++) {
! 1348: if (!NSSOCKADDR6(i))
! 1349: continue;
! 1350: if ( addrcmp( (void *) &(NSSOCKADDR6(i)->sin6_addr),
! 1351: (void *) &(from6->sin6_addr), AF_INET6 ) == 0 )
! 1352: break;
! 1353: }
! 1354: if (i == NSCOUNT6) {
! 1355: snprintf(tempstring, sizeof(tempstring),
! 1356: "Resolver error: Received reply from unknown source: %s",
! 1357: inet_ntop( AF_INET6, &(from6->sin6_addr), addrstr,
! 1358: sizeof addrstr ));
! 1359: restell(tempstring);
! 1360: } else
! 1361: parserespacket((byte *)resrecvbuf,r);
! 1362: } else {
! 1363: snprintf(tempstring, sizeof(tempstring), "Resolver: Socket error: %s",strerror(errno));
! 1364: restell(tempstring);
! 1365: }
! 1366: }
! 1367: #endif
! 1368:
! 1369:
! 1370: int istime(double x,double *sinterval)
! 1371: {
! 1372: if (x) {
! 1373: if (x > sweeptime) {
! 1374: if (*sinterval > x - sweeptime)
! 1375: *sinterval = x - sweeptime;
! 1376: } else
! 1377: return 1;
! 1378: }
! 1379: return 0;
! 1380: }
! 1381:
! 1382:
! 1383: void dns_events(double *sinterval)
! 1384: {
! 1385: struct resolve *rp,*nextrp;
! 1386:
! 1387: for (rp = expireresolves;(rp) && (sweeptime >= rp->expiretime);rp = nextrp) {
! 1388: nextrp = rp->next;
! 1389: switch (rp->state) {
! 1390: case STATE_FINISHED: /* TTL has expired */
! 1391: case STATE_FAILED: /* Fake TTL has expired */
! 1392: if (debug) {
! 1393: snprintf(tempstring, sizeof(tempstring), "Resolver: Cache record for \"%s\" (%s) has expired. (state: %u) Marked for expire at: %g, time: %g.",
! 1394: nonull(rp->hostname), strlongip( &(rp->ip) ),
! 1395: rp->state, rp->expiretime, sweeptime);
! 1396: restell(tempstring);
! 1397: }
! 1398: unlinkresolve(rp);
! 1399: break;
! 1400: case STATE_PTRREQ1: /* First T_PTR send timed out */
! 1401: resendrequest(rp,T_PTR);
! 1402: restell("Resolver: Send #2 for \"PTR\" query...");
! 1403: rp->state++;
! 1404: rp->expiretime = sweeptime + ResRetryDelay2;
! 1405: (void)istime(rp->expiretime,sinterval);
! 1406: res_resend++;
! 1407: break;
! 1408: case STATE_PTRREQ2: /* Second T_PTR send timed out */
! 1409: resendrequest(rp,T_PTR);
! 1410: restell("Resolver: Send #3 for \"PTR\" query...");
! 1411: rp->state++;
! 1412: rp->expiretime = sweeptime + ResRetryDelay3;
! 1413: (void)istime(rp->expiretime,sinterval);
! 1414: res_resend++;
! 1415: break;
! 1416: case STATE_PTRREQ3: /* Third T_PTR timed out */
! 1417: restell("Resolver: \"PTR\" query timed out.");
! 1418: failrp(rp);
! 1419: (void)istime(rp->expiretime,sinterval);
! 1420: res_timeout++;
! 1421: break;
! 1422: }
! 1423: }
! 1424: if (expireresolves)
! 1425: (void)istime(expireresolves->expiretime,sinterval);
! 1426: }
! 1427:
! 1428:
! 1429: char *dns_lookup2(ip_t * ip)
! 1430: {
! 1431: struct resolve *rp;
! 1432:
! 1433: if ((rp = findip(ip))) {
! 1434: if ((rp->state == STATE_FINISHED) || (rp->state == STATE_FAILED)) {
! 1435: if ((rp->state == STATE_FINISHED) && (rp->hostname)) {
! 1436: if (debug) {
! 1437: snprintf(tempstring, sizeof(tempstring), "Resolver: Used cached record: %s == \"%s\".\n",
! 1438: strlongip(ip),rp->hostname);
! 1439: restell(tempstring);
! 1440: }
! 1441: return rp->hostname;
! 1442: } else {
! 1443: if (debug) {
! 1444: snprintf(tempstring, sizeof(tempstring), "Resolver: Used failed record: %s == ???\n",
! 1445: strlongip(ip));
! 1446: restell(tempstring);
! 1447: }
! 1448: return NULL;
! 1449: }
! 1450: }
! 1451: return NULL;
! 1452: }
! 1453: if (debug)
! 1454: fprintf(stderr,"Resolver: Added to new record.\n");
! 1455: rp = allocresolve();
! 1456: rp->state = STATE_PTRREQ1;
! 1457: rp->expiretime = sweeptime + ResRetryDelay1;
! 1458: addrcpy( (void *) &(rp->ip), (void *) ip, af );
! 1459: linkresolve(rp);
! 1460: addrcpy( (void *) &(rp->ip), (void *) ip, af );
! 1461: linkresolveip(rp);
! 1462: sendrequest(rp,T_PTR);
! 1463: return NULL;
! 1464: }
! 1465:
! 1466:
! 1467: char *dns_lookup(ip_t * ip)
! 1468: {
! 1469: char *t;
! 1470:
! 1471: if (!dns) return NULL;
! 1472: t = dns_lookup2(ip);
! 1473: return (t && use_dns) ? t : NULL;
! 1474: }
! 1475:
! 1476: #ifdef ENABLE_IPV6
! 1477: /* Returns an ip6.arpa character string. */
! 1478: void addr2ip6arpa( ip_t * ip, char * buf ) {
! 1479: unsigned char * p = (unsigned char *) ip;
! 1480: char * b = buf;
! 1481: int i;
! 1482:
! 1483: for ( i = sizeof (struct in6_addr) - 1; i >= 0; i-- ) {
! 1484: sprintf( b, "%x.%x.", p[i] % 16, p[i] >> 4 );
! 1485: b += 4;
! 1486: }
! 1487: sprintf( b, "ip6.arpa" );
! 1488: return;
! 1489: }
! 1490: #endif
! 1491:
! 1492: /* Resolve an IP address to a hostname. */
! 1493: struct hostent *addr2host( const char *addr, int af ) {
! 1494: int len = 0;
! 1495: switch ( af ) {
! 1496: case AF_INET:
! 1497: len = sizeof( struct in_addr );
! 1498: break;
! 1499: #ifdef ENABLE_IPV6
! 1500: case AF_INET6:
! 1501: len = sizeof( struct in6_addr );
! 1502: break;
! 1503: #endif
! 1504: }
! 1505: return gethostbyaddr( addr, len, af );
! 1506: }
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>