Annotation of embedaddon/mtr/dns.c, revision 1.1.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>