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